Создание повторно используемых компонентов формы с использованием библиотеки Formik и Yup для React + Vite

Я пытаюсь создать проект реагирования + vite, в котором я пытаюсь реализовать повторно используемые компоненты формы, используя Formik и Yup, но пока не могу этого добиться. Я создал компонент под названием <AppInputField/>, который представляет собой просто поле <input/> с пользовательским CSS, соответствующим моему дизайну всего веб-сайта. У меня похожее <AppButton/>, опять же просто <button/>. И все необходимые атрибуты я передаю через реквизит. Теперь, когда я пытаюсь создать нечто подобное для <AppForm/>, которое будет охватывать formik библиотеку, мне трудно ее решить. В результате поисков я узнал, что это связано useFormik() и useFormikContext(), но опять же не уверен на 100%. Вот мои коды:

SignUp.jsx

const SignUp = () => {
  
const signUpSchema = Yup.object({
  name: Yup.string().min(2).max(25).required("Please enter your name"),
  });

  return (
    <>
    <AppForm
        initialValues = {{
            name : ''
        }}
        validationSchema = {signUpSchema}
        onSubmit = {(values) => {console.info("Submitted with these values\n" + values)}}
    >
        <AppInputField 
          name='name'
          label='Enter your name'
          placeholder='XYZ'
        />
        <SubmitButton title='Register'/>
    </AppForm>
    </>
  );
};

export default SignUp;

AppForm.js

function AppForm({initialValues, onSubmit, validationSchema, children}) {
    return (
        <Formik
            initialValues = { initialValues }
            onSubmit = { onSubmit }
            validationSchema = { validationSchema } 
        >
                {children}
                {/* children passed as props here are the inner components of form 
meaning AppInputField and SubmitButton
this actually renders the inside components */}
        </Formik>
    );
}
export default AppForm;

AppInputField.jsx

const AppInputField = ({name, label, placeholder, type='text') => {
    const { handleChangeEvent, handleBlur, values } = useFormikContext();
    return (
        <>
        <label htmlFor = {name} className = "input-label">{label}</label>
        <input
            autoComplete = "off"
            className = "input-text"
            id = {name}
            name = {name} 
            onChange = {handleChangeEvent}
            onBlur = {handleBlur}
            placeholder = {placeholder}
            type = {type}
            value = {values[name]}
        />
        </>
    )
}
export default AppInputField

SubmitButton.jsx

function SubmitButton({title}) {
    const { handleSubmit } = useFormikContext();
    return (
        <AppButton 
            title = {title} 
            type='submit' 
            onClick = {handleSubmit}
        />
    );
}
export default SubmitButton;

Итак, ошибка при нажатии на кнопку SubmitButton Uncaught TypeError: Cannot destructure property 'handleSubmit ' of 'useFormikContext(...)' as it is undefined. Если я изменю его на что-то submitForm, возникнет та же ошибка. Также при использовании useFormik() код компонентов меняется, но тоже безуспешно. При использовании useFormik я не могу использовать контекст в другом компоненте. Мне нужно использовать все в одной форме в одном jsx-файле. Надеюсь, я смогу объяснить свою цель. С подобной абстракцией я столкнулся, проходя курс реактив-натива Моша Хемдани. И мне это показалось настолько прекрасным, что я хочу добиться этого в своем react+vite проекте. Любая помощь будет оценена по достоинству.

Для ввода, который вам нужен formik.org/docs/api/useField. Но useFormikContext не должен выдавать ошибку, независимо от того, смотрите ли вы на свой код. Вы больше никуда не звоните AppInputField? (опубликованный код является 100% отражением?). И все ли эти компоненты являются частью одного пакета NPM?

adsy 07.04.2024 07:54

Да, AppInputField также используется на странице входа, аналогично регистрации. Я не получаю тот же вопрос о пакете NPM. В моих зависимостях есть: ` "@auth0/auth0-react": "^2.2.4", "axios": "^1.6.8", "bootstrap": "^5.3.3", "formik" : "^2.4.5", "реагировать": "^18.2.0", "реагировать-dom": "^18.2.0", "реагировать-маршрутизатор-dom": "^6.22.3", "ага" : "^1.4.0" ` И спасибо, что поделились документом useField. Будет проверено

Tony Riddle 07.04.2024 09:45
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
236
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Понятно! хотел бы поделиться со всеми вами. useField это было здорово, и спасибо Адси за руководство. Вот мой код с Ага и Формиком...

AppForm.jsx

const AppForm = ({initialValues, validationSchema, onSubmit, children}) => (
  <>
    <Formik
      initialValues = {initialValues}
      validationSchema = {validationSchema}
      onSubmit = {onSubmit}
    >
      {(formikProps) => (
        <Form>


            {React.Children.map(children, child => {
                if (React.isValidElement(child)) {
                  React.cloneElement(child);
                }
                return child;
            })}
        </Form>
      )}
    </Formik>
  </>
);
export default AppForm

AppInputField.jsx

const AppFormInputField = ({label, type='text', ...props}) => {
    const [field, meta, helpers] = useField(props);
  return (
    <>
        <AppInputField label = {label} type = {type} {...field} {...props}/>
        <ErrorMessage error = {meta.error} visible = {meta.touched && meta.error} />
    </>
  )
}

export default AppFormInputField

AppFormFileUpload.jsx

const AppFormFileUpload = ({label, allowedExtensions, setFieldValue, ...props}) => {
    const [field, meta, helpers] = useField(props);
  return ( 
    <>
{/*FileUploadField is basically input field with attribute type=file with custom css*/}
      <FileUploadField label = {label} {...field} {...props}  
        value = {undefined}
        onChange = {(event) => {
          helpers.setValue(event.target.files)
        }}
      />
      <ErrorMessage error = {meta.error} visible = {meta.touched && meta.error}/>
    </>
  )
}

export default AppFormFileUpload

Без изменений SubmitButton.jsx

SignUp.jsx

const SignUp = () => {

  const checkSchema = Yup.object({
    firstName: Yup.string().min(3).required("First Name is Required"),
    file : Yup.mixed().required('required')
    .test('fileFormat', 'Only approved files are allowed', (value, context) => {
      if (value) {//just pretest check
        const supportedFormats = ['pdf','jpg', 'gif', 'png', 'jpeg', 'svg', 'webp'];
        for (const [key, val] of Object.entries(value)) {
          if (!supportedFormats.includes(val.name.split('.').pop())) return false
        }
      }
      return true;
    })
    .test('fileSize', 'File size must be less than 3MB', (value, context) => {
      if (value) {//just pretest check
        for (const [key, val] of Object.entries(value)) {
          if (val.size > 3145728) return false
        }
      }
      return true;
    }),
  })

  const initialValues = {
    firstName: '',
    file : ''
  }

  const handleSubmit = (values, actions) => {console.info(values)}

  return (
    <>
    <AppForm
      initialValues = {initialValues}
      validationSchema = {checkSchema}
      onSubmit = {handleSubmit}
    >
      <AppFormInputField name='firstName' label='Enter First Name' />
      <AppFormFileUpload name='file' multiple/>
      <SubmitButton title='Submit' />    
    </AppForm>
    </>
  );
};

export default SignUp;

Надеюсь, это решение может быть полезным... Таким образом, формы можно будет повторно использовать с соответствующими формами и проверкой.

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