#reactjs #react-hook-form
Вопрос:
У меня есть три компонента для формы:
- CreateInvoice.js (Форма родительского компонента)
- Item.js (Дочерний компонент)
- 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. Сейчас же! Все работает так, как и ожидалось, Большое вам спасибо