Я пытаюсь создать проект реагирования + 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
проекте. Любая помощь будет оценена по достоинству.
Да, 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
. Будет проверено
Понятно! хотел бы поделиться со всеми вами. 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;
Надеюсь, это решение может быть полезным... Таким образом, формы можно будет повторно использовать с соответствующими формами и проверкой.
Для ввода, который вам нужен formik.org/docs/api/useField. Но
useFormikContext
не должен выдавать ошибку, независимо от того, смотрите ли вы на свой код. Вы больше никуда не звонитеAppInputField
? (опубликованный код является 100% отражением?). И все ли эти компоненты являются частью одного пакета NPM?