Прошло 3 месяца, как я изучаю ReactJS + TypeScript. Мой вопрос касается использования формы реагирования-крюка (v7) для редактирования формы. Я хочу использовать свой собственный компонент, который я создал и сам нашел, как это сделать!
Вот часть моего провайдера формы с формой реакции-хука
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import InputText from 'components/commons/form/InputText';
import { supabase } from 'configs/supabase';
const EditEducation: React.FC = () => {
const { educationId } = useParams();
const [education, setEducation] = useState<education>();
const getEducation = async (educationId: string | undefined) => {
try {
const { data, error } = await supabase
.from('tables1')
.select('data1, data2')
.eq('id', educationId)
.single();
if (error) {
seterror(error.message);
}
if (data) {
return data;
}
} catch (error: any) {
alert(error.message);
}
};
useEffect(() => {
getEducation(educationId).then((data) => {
setEducation(data);
});
// eslint-disable-next-line
}, [educationId]);
const methods = useForm();
const onSubmit = async (formData: any) => {
const updateData = {
data1 = formData.data1,
data2 = formData.data2
};
try {
setSaving(true);
const { error } = await supabase.from('educations').update(updateData);
if (error) {
seterror(error.message);
}
if (!error) {
navigate('/experiences/education');
}
setSaving(false);
} catch (error: any) {
seterror(error.message);
}
};
return (
...
<FormProvider {...methods}>
<form className = "p-4" onSubmit = {methods.handleSubmit(onSubmit)}>
<InputText
id = "data1"
label = "Data1"
placeholder = "Ex: data1"
defaultValue = {education?.data1}
options = {{ required: 'This field is required' }}
/>
<Button type = "submit">{saving ? 'Saving' : 'Save'}</Button>
</form>
</FormProvider>
...
)
};
Вот мой пользовательский компонент:
import React, { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
interface InputProps {
id: string;
label: string;
placeholder?: string;
defaultValue?: string;
}
const InputText: React.FC<InputProps> = ({
id,
label,
placeholder,
defaultValue,
options,
...rest
}: InputProps) => {
const {
register,
setValue,
formState: { errors }
} = useFormContext();
useEffect(() => {
if (defaultValue) setValue(id, defaultValue, { shouldDirty: true });
}, [defaultValue, setValue, id]);
return (
<div className = "">
<label htmlFor = {id} className = "">
{label}
</label>
<input
type = "text"
placeholder = {placeholder}
className = ""
id = {id}
defaultValue = {defaultValue}
{...register(id, options)}
{...rest}
/>
{errors[id] && (
<p className = "">
<span className = "">*</span> {errors[id]?.message}
</p>
)}
</div>
);
};
export default InputText;
Как видите, я использовал formContext, потому что хочу разбить свой код на более мелкие компоненты.
Теперь у меня есть некоторые сомнения, правильно ли я кодирую, особенно когда я использую формы редактирования ut: если установить значение по умолчанию с помощью опоры «defaultValue», я должен отправить (показать ошибку), а затем щелкнуть внутри ввода, чтобы изменить состояние по порядку убрать ошибку во входном компоненте.
Вот почему я добавил хук useEffect для очистки ошибки проверки ввода, и он работает. Что Вы думаете об этом ? Есть ли лучший способ управлять им (я думаю, да, это более чистый способ установить схему проверки)?
Заранее спасибо и извините за мой ржавый английский. Всем хорошего дня и надеюсь, что мой код поможет людям.
Используйте <FormProvider {...methods}>, и он работает, но я не знаю, хороший ли это способ сделать это.
Редактировать: на самом деле мне нужно дважды отправить, чтобы получить мои данные, поэтому я думаю, что это неправильный способ, какие-либо предложения?
Edit2: я нашел «решение»: если у меня есть defaultValue в моих реквизитах, я делаю это в своем компоненте:
useEffect(() => {
if (defaultValue) setValue(id, defaultValue, { shouldDirty: true });
}, [defaultValue, setValue, id]);
Не думаю, что это лучшее решение...
Прошло 3 месяца, как я изучаю ReactJS + TypeScript. Мой вопрос касается использования формы реагирования-крюка (v7) для редактирования формы. Я хочу использовать свой собственный компонент, который я создал и сам нашел, как это сделать!
editForm.tsx
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import InputText from 'components/commons/form/InputText';
import { supabase } from 'configs/supabase';
const EditEducation: React.FC = () => {
const { educationId } = useParams();
const [education, setEducation] = useState<education>();
...
const getEducation = async (educationId: string | undefined) => {
try {
const { data, error } = await supabase
.from('tables1')
.select('data1, data2')
.eq('id', educationId)
.single();
if (error) {
seterror(error.message);
}
if (data) {
return data;
}
} catch (error: any) {
alert(error.message);
}
};
useEffect(() => {
getEducation(educationId).then((data) => {
setEducation(data);
});
// eslint-disable-next-line
}, [educationId]);
const methods = useForm();
const onSubmit = async (formData: any) => {
const updateData = {
data1 = formData.data1,
data2 = formData.data2
};
try {
setSaving(true);
const { error } = await supabase.from('educations').update(updateData);
if (error) {
seterror(error.message);
}
if (!error) {
navigate('/experiences/education');
}
setSaving(false);
} catch (error: any) {
seterror(error.message);
}
};
return (
<FormProvider {...methods}>
<form className = "p-4" onSubmit = {methods.handleSubmit(onSubmit)}>
<InputText
id = "data1"
label = "Data1"
placeholder = "Ex: data1"
defaultValue = {education?.data1}
options = {{ required: 'This field is required' }}
/>
<Button type = "submit">{saving ? 'Saving' : 'Save'}</Button>
</form>
</FormProvider>
)
...
myCustomComponent.tsx
import React, { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
interface InputProps {
id: string;
label: string;
placeholder?: string;
defaultValue?: string;
}
const InputText: React.FC<InputProps> = ({
id,
label,
placeholder,
defaultValue,
options,
...rest
}: InputProps) => {
const {
register,
setValue,
formState: { errors }
} = useFormContext();
useEffect(() => {
if (defaultValue) setValue(id, defaultValue, { shouldDirty: true });
}, [defaultValue, setValue, id]);
return (
<div className = "">
<label htmlFor = {id} className = "">
{label}
</label>
<input
type = "text"
placeholder = {placeholder}
className = ""
id = {id}
defaultValue = {defaultValue}
{...register(id, options)}
{...rest}
/>
{errors[id] && (<p className = "">
<span className = "">*</span> {errors[id]?.message}
</p>)}
</div>
);
};
export default InputText;
Как видите, я использовал formContext, потому что хочу разбить свой код на более мелкие компоненты. Теперь у меня есть некоторые сомнения, правильно ли я кодирую, особенно когда я использую формы редактирования ut: если установить значение по умолчанию с помощью опоры «defaultValue», я должен отправить (показать ошибку), а затем щелкнуть внутри ввода, чтобы изменить состояние по порядку убрать ошибку во входном компоненте.
Вот почему я добавил хук useEffect для очистки ошибки проверки ввода, и он работает. Что Вы думаете об этом ? Есть ли лучший способ управлять им (я думаю, да, это более чистый способ установить схему проверки)? Заранее спасибо и извините за мой ржавый английский. Всем хорошего дня и надеюсь, что мой код поможет людям.
Edit1: На самом деле мне нужно дважды отправить, чтобы получить мои данные, поэтому я думаю, что это неправильный способ, какие-либо предложения?
Edit2: я нашел «решение»: если у меня есть defaultValue в моих реквизитах, я делаю это в своем пользовательском компоненте:
useEffect(() => {
if (defaultValue) setValue(id, defaultValue, { shouldDirty: true });
}, [defaultValue, setValue, id]);
Не думаю, что это лучшее решение...
Edit3: Спасибо @Jérémy Rippert, это мое рабочее решение:
editForm.tsx
...
const methods = useForm();
const { reset } = methods;
useEffect(() => {
reset(education);
}, [reset, education]);
return (
<FormProvider {...methods}>
<form className = "p-4" onSubmit = {methods.handleSubmit(onSubmit)}>
<InputText
id = "degree"
label = "Degree"
placeholder = "Ex: Master 2 - Design & Marketing"
options = {{ required: 'This field is required' }}
/>
</form>
</FormProvider>
)
...
myCustomComponent.tsx
...
const InputText: React.FC<InputTextProps> = ({
id,
label,
placeholder,
options
}: InputTextProps) => {
const {
register,
formState: { isDirty, isValid, touchedFields, dirtyFields, errors }
} = useFormContext();
return (
<input
type = "text"
placeholder = {placeholder}
className = {`block w-full rounded-lg border ${
errors[id] ? 'border-red-600' : 'border-gray-600'
} bg-gray-700 p-2.5 text-sm text-white placeholder-gray-400 focus:outline-none`}
id = {id}
{...register(id, options)}
/>
)
...
Еще раз спасибо @Jérémy Rippert
@ alexcool68 рад, что вы нашли решение! Однако я думаю, что вы отредактировали мой комментарий вместо своего сообщения (это первый раз, когда я отвечаю на сообщение, поэтому я не был уверен, отредактировали ли вы мой ответ, извините)
Вы правы, я отредактировал ваш комментарий вместо того, чтобы подтвердить ваш ответ, и это была ошибка. Я не нашел, как восстановить его, поэтому я думаю, что это был ваш звонок, и только вы можете повторно отредактировать свой комментарий, так что вы сделали хорошо! Merci encore pour ta réponse en tout cas, si je peux faire quelque selected pour te donner les points ou change un truc dis le moi, je connais pas trop Stackoverflow encore ...
Мы оба изучаем, как работает SO, ахах, это круто. Довольна вашим помощником! Franchement super que tu aies réussi à mettre en place react-hook-form alors que tu as start le react / TS il y à peine 3 mois, gg! Je crois que ma réponse originale m'a donné des points aussi grâce à ton upvote, merci :)
Pas de soucis, j'ai mis ta réponse en "réponse" donc tu as full crédit! Oui j'apprends vite et c'est pas trop compliqué pour le moment.
Я неправильно отредактировал свой предыдущий ответ, вот оригинал:
Вы должны указать значения по умолчанию для useForm, а не для вашего компонента (поэтому вашему InputText не нужно знать о defaultValue или setValue, он будет иметь правильное значение благодаря методу регистрации).
Чтобы инициализировать форму, вы можете сделать
useForm({ defaultValues: { data1: education?.data1 } });
Если данные, которые вы используете для предоставления значений по умолчанию, загружаются после инициализации формы, вы можете использовать метод сброса (см. документы), который я лично добавил в useEffect для отслеживания обновления данных:
const Component: React.FC = ({ defaultValues }) => {
const {
register,
handleSubmit,
reset,
} = useForm({ defaultValues });
useEffect(() => {
reset(defaultValues);
}, [defaultValues, reset]);
return ...
}
С другой стороны, вы должны определить getEducation в вызывающем его useEffect, а не в компоненте, чтобы метод не объявлялся каждый раз при визуализации вашего компонента. Фрагмент:
useEffect(() => {
const getEducation = () => {
...
};
getEducation();
}, [educationId]);
Salut Jérémy (je continu quand même en anglais), я поместил свои fetchData в useEffect, теперь все в порядке (пока не могу редактировать свой пост). Я пытаюсь передать defaultValues в useForm, и даже если я передаю все данные, на моем вводе у меня ничего нет, если я не напишу в кавычки " " значение по умолчанию: code defaultValue: {data1: education.data1 code -> не работает, code defaultValue :{data1: "пример" code -> работает. Мне не нужно передавать его моему компоненту, это правда, просто нужно найти, почему ему не нужен мой объект.