Ошибка типа: регистрация не является функцией в форме react-hook

#reactjs #react-hook-form

Вопрос:

У меня есть три компонента для формы:

  1. CreateInvoice.js (Форма родительского компонента)
  2. Item.js (Дочерний компонент)
  3. Input.js (простой ввод с некоторым стилем) Когда я пытаюсь получить доступ к register методу в Item.js файл , использующий этот код const { register } = useFormContext(); , показывает мне это сообщение об ошибке
 TypeError: register is not a function
Input
src/components/Input.js:5
  2 | 
  3 | const Input = ({ inputName, readOnly, register }) => {
  4 |     return (
> 5 |         <input {...(readOnly amp;amp; { disabled: true, readOnly, value: 0 })} type="text" id={inputName} className="w-full bg-primaryOne p-3 rounded-md shadow-md border border-borderOne focus:outline-none focus:border-secondaryOne transition text-white font-bold text-xs" {...register(inputName, { required: true })} />
  6 |     )
  7 | }
  8 | 
 

Но когда я прямо позвоню нам, мы войдем Item.js, он не показывает мне сообщение об ошибке, и когда я добавляю новый элемент в форму, он добавляет пустой объект в массив счетов-фактур, как это.
введите описание изображения здесь

Кто-нибудь, пожалуйста, помогите мне это исправить.

Код входного компонента(Input.js):

 import React from 'react'

const Input = ({ inputName, readOnly, register }) => {
    return (
        <input {...(readOnly amp;amp; { disabled: true, readOnly, value: 0 })} type="text" id={inputName} className="w-full bg-primaryOne p-3 rounded-md shadow-md border border-borderOne focus:outline-none focus:border-secondaryOne transition text-white font-bold text-xs" {...register(inputName, { required: true })} />
    )
}

export default Input

 

Весь код формы(CreateInvoice.js):

 import React, { useState } from 'react'
import { useForm, Controller, useFieldArray, FormProvider } from "react-hook-form";
import DatePicker from 'react-datepicker'
import "react-datepicker/dist/react-datepicker.css";
import Label from './Label';
import Input from './Input';
import Item from './Item';
// import { useDispatch } from 'react-redux';
// import { createInvoice } from '../actions/invoices';

const CreateInvoice = ({ openForm, setOpenForm }) => {
    const { register, control, handleSubmit, errors } = useForm();
    const [newItems, setNewItems] = useState([]);

    const { fields, append, remove } = useFieldArray({
        control,
        name: "invoices"
    });
    // const dispatch = useDispatch();

    const onSubmit = data => {
        console.log(data);
        // dispatch(createInvoice(data));
    };
    return (
        <div className={`transition ${!openForm ? 'transform translate-x-full hidden' : '-translate-x-full'}`}>
            <div className="fixed top-0 left-0 flex items-center justify-center w-full h-screen z-10" onClick={() => setOpenForm(!openForm)}></div>
            <div className="fixed top-0 left-0 z-20 ml-24">
                <FormProvider >
                    <form onSubmit={handleSubmit(onSubmit)} className="w-screen max-w-2xl h-screen bg-primaryTwo p-14">
                        <h1 className="text-white text-2xl font-bold mb-10">Create Invoice</h1>
                        <div className="overflow-scroll w-full h-full flex flex-col pr-7 content-area pb-10">
                            <small className="text-secondaryTwo font-bold text-xs">Bill Form</small>
                            <div>
                                <Label labelName="Street Address" />
                                <Input inputName="streetAddress" register={register} />
                            </div>
                            <div className="flex justify-between flex-wrap">
                                <div>
                                    <Label labelName="City" />
                                    <Input inputName="city" register={register} />
                                </div>
                                <div>
                                    <Label labelName="Post Code" />
                                    <Input inputName="postCode" register={register} />
                                </div>
                                <div>
                                    <Label labelName="Country" />
                                    <Input inputName="country" register={register} />
                                </div>
                            </div>
                            <small className="text-secondaryTwo font-bold text-xs mt-8">Bill To</small>
                            <div>
                                <Label labelName="Client Name" />
                                <Input inputName="clientName" register={register} />
                            </div>
                            <div>
                                <Label labelName="Client Email" />
                                <Input inputName="clientEmail" register={register} />
                            </div>
                            <div>
                                <Label labelName="Street Address" />
                                <Input inputName="clientStreetAddress" register={register} />
                            </div>
                            <div className="flex flex-wrap justify-between">
                                <div>
                                    <Label labelName="City" />
                                    <Input inputName="clientCity" register={register} />
                                </div>
                                <div>
                                    <Label labelName="Post Code" />
                                    <Input inputName="clientPostCode" register={register} />
                                </div>
                                <div>
                                    <Label labelName="Country" />
                                    <Input inputName="clientCountry" register={register} />
                                </div>
                            </div>
                            <div className="flex justify-between">
                                <div className="w-1/2 mr-2">
                                    <Label labelName="Invoice Date" />
                                    <Controller
                                        control={control}
                                        name="paymentDue"
                                        render={({ field }) => (
                                            <DatePicker
                                                className="w-full bg-primaryOne p-3 rounded-md shadow-md border border-borderOne focus:outline-none focus:border-secondaryOne transition text-white font-bold text-xs"
                                                onChange={(date) => field.onChange(date)}
                                                selected={field.value}
                                            />
                                        )}
                                    />
                                </div>
                                <div className="w-1/2 ml-2">
                                    <Label labelName="Payment Terms" />
                                    <select className="w-full bg-primaryOne p-3 rounded-md shadow-md border border-borderOne focus:outline-none focus:border-secondaryOne transition text-white font-bold text-xs" name="Payments Term" id="Payments Term" {...register("Payments Term", { required: true })}>
                                        <option value="1">Next 1 Day</option>
                                        <option value="7">Next 7 Days</option>
                                        <option value="14">Next 14 Days</option>
                                        <option value="30">Next 30 Days</option>
                                    </select>
                                </div>
                            </div>
                            <div>
                                <Label labelName="Descriptions" />
                                <Input inputName="descriptions" register={register} />
                            </div>
                            <p className="text-gray-500 text-lg mt-6 mb-2 font-bold">Item List</p>
                            <div>
                                // in this code I need help
                                {fields.map((invoice, index) => <Item key={invoice.id} index={index} remove={remove} />)}
                            </div>
                            <button className="w-full bg-borderOne hover:bg-primaryOne transition text-white border-none rounded-full mt-4 p-4 text-xs font-bold flex justify-center" onClick=
                                {e => {
                                    e.preventDefault();
                                    append({});
                                }}
                            >
                                <span className="font-semibold mr-1"> </span>Add New Item
                            </button>
                        </div>
                        <div className="flex justify-between py-4">jsx

                            <button className="rounded-full text-neutral text-xs bg-primaryOne outline-none px-8 py-4 font-bold" onClick={() => setOpenForm(!openForm)}>Discard</button>
                            <div className="pr-7">
                                <button className="rounded-full text-neutral text-xs bg-primaryOne outline-none px-8 py-4 font-bold">Save as Draft</button>
                                <input className="rounded-full text-neutral text-xs bg-secondaryTwo outline-none ml-2 px-8 py-4 font-bold" type="submit" value="Save amp; Send" />
                            </div>
                        </div>
                    </form>
                </FormProvider>
            </div >

        </div >
    )
}

export default CreateInvoice
 

весь дочерний компонент(Item.js) код

 import React, { useState } from 'react'
import Input from './Input'
import Label from './Label'
import { useFormContext } from "react-hook-form";

const Item = ({ index, remove }) => {
    const { register } = useFormContext();

    return (
        <div className="flex justify-center items-end">
            <div className="w-3/5">
                <Label labelName="Item Name" />
                <Input inputName="inputName" register={register} />
            </div>
            <div className="w-2/12 mx-3">
                <Label labelName="Qty." />
                <Input inputName="quantity" register={register} />
            </div>
            <div className="w-1/3">
                <Label labelName="Price" />
                <Input inputName="price" register={register} />
            </div>
            <div className="mx-3">
                <Label labelName="Total" />
                <Input inputName="total" register={register} readOnly />
            </div>
            <button className="mb-4" aria-label="delete button" onClick={
                e => {
                    e.preventDefault();
                    remove(index);
                }}
            >
                <svg className="transition fill-current text-gray-400 hover:fill-current hover:text-red-400" width="13" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M11.583 3.556v10.666c0 .982-.795 1.778-1.777 1.778H2.694a1.777 1.777 0 01-1.777-1.778V3.556h10.666zM8.473 0l.888.889h3.111v1.778H.028V.889h3.11L4.029 0h4.444z" fillRule="nonzero" /></svg></button>
        </div>
    )
}

export default Item
 

Ответ №1:

Вам не хватает, чтобы распространить formMethods <FormProvider /> это на ваш <CreateInvoice /> компонент.

 const CreateInvoice = ({ openForm, setOpenForm }) => {
    const formMethods = useForm();
    const { register, control, handleSubmit, formState: { errors } } = formMethods;
    
    return (
      <FormProvider {...formMethods} >
      ...
      </FormProvider>
    );
}
 

Для второго выпуска:

  • вы неправильно регистрируете компоненты элемента массива полей <input /> и пропускаете настройку index , поэтому RHF не может настроить ссылку на это fields . Проверьте демонстрационную версию, я только что передал ее в fieldId качестве опоры вашему <Item /> компоненту.
  • поскольку errors объект v7 RHF является formState свойством возвращаемого useForm свойства . Я обновил приведенный выше пример кода.
  • вы должны установить элемент defaultValues для массива полей при вызове append . Из документов:

Когда вы append , prepend , insert и update массив полей, объект obj не может быть пустым объектом, а должен содержать все ваши входные defaultValues данные .

Изменить форму крючка реакции - Базовая (раздвоенная)

Комментарии:

1. спасибо за вашу помощь. Теперь я не получаю сообщение об ошибке, но я не могу отправить свою форму.

2. Вы заполнили все поля, когда тестировали его? Потому что вы устанавливаете обязательность каждого <Input /> компонента. onSubmit сработает только тогда, когда в вашей форме не будет ошибок. Вы можете проверить это, зарегистрировав errors объект в своем <Createinvoice /> компоненте и посмотрев, является ли он пустым или нет.

3. Когда я не добавляю новый элемент в форму, он отправляет форму, но когда я добавляю новый элемент в форму, он не отправляет форму. Ссылка на веб-сайт: счет- фактура-веб-приложение.vercel.app

4. Это работает! Спасибо вам за то, что делаете все возможное и невозможное!

5. Сейчас же! Все работает так, как и ожидалось, Большое вам спасибо