Редактировать форму с пользовательским компонентом для формы реакции-крюка: значение по умолчанию

Прошло 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]);

Не думаю, что это лучшее решение...

Подъем в javascript
Подъем в javascript
Hoisting - это поведение в JavaScript, при котором переменные и объявления функций автоматически "перемещаются" в верхнюю часть соответствующих...
Хук useOnClickOutside в ReactJS
Хук useOnClickOutside в ReactJS
Как разработчик ReactJS, вы, возможно, сталкивались с ситуацией, когда вам нужно закрыть модальное или выпадающее меню, когда кто-то щелкает за его...
Хуки (часть-2) - useEffect
Хуки (часть-2) - useEffect
Хук useEffect - один из самых мощных и универсальных инструментов в арсенале разработчика React. Он позволяет вам управлять побочными эффектами в...
[LXI-SpartaCodingClub Full-Stack Bootcamp in Indonesia] 2023/1/21 TIL/Week 15]
[LXI-SpartaCodingClub Full-Stack Bootcamp in Indonesia] 2023/1/21 TIL/Week 15]
Я научился создавать карусель в ReactJS с помощью библиотеки Splide.
Краткое введение в Styled-компоненты
Краткое введение в Styled-компоненты
В настоящее время популярность Styled-компонентов становится все больше и больше. Большинство проектов, построенных на React.js, используют эту...
ДЕНЬ 8 | Страница обзора в React
ДЕНЬ 8 | Страница обзора в React
На этом сегодня все, завтра снова увидимся с новым проектом!
0
0
377
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Прошло 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

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 -> работает. Мне не нужно передавать его моему компоненту, это правда, просто нужно найти, почему ему не нужен мой объект.

alexcool68 21.11.2022 20:36

@ alexcool68 рад, что вы нашли решение! Однако я думаю, что вы отредактировали мой комментарий вместо своего сообщения (это первый раз, когда я отвечаю на сообщение, поэтому я не был уверен, отредактировали ли вы мой ответ, извините)

Jérémy Rippert 22.11.2022 17:26

Вы правы, я отредактировал ваш комментарий вместо того, чтобы подтвердить ваш ответ, и это была ошибка. Я не нашел, как восстановить его, поэтому я думаю, что это был ваш звонок, и только вы можете повторно отредактировать свой комментарий, так что вы сделали хорошо! 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 ...

alexcool68 22.11.2022 21:14

Мы оба изучаем, как работает 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 :)

Jérémy Rippert 23.11.2022 10:37

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.

alexcool68 23.11.2022 14:06
Ответ принят как подходящий

Я неправильно отредактировал свой предыдущий ответ, вот оригинал:

Вы должны указать значения по умолчанию для 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]);

Другие вопросы по теме