подробнее:
есть задача, получаем набор полей формы - необходимо отрисовать эти поля, поля валидируют сами себя с помощью хуков, которые добавляют ошибки валидации в стор
return (
<Form initialValues={initialValues} validate={validate} onSubmit={handleSubmit} ref={formRef}>
{({ touched, values, setFieldValue, setFieldTouched }) => {
return (
<>
…
{условие && (
<FormGenerator
forms={templates[currTemplate.value]?.forms}
touched={touched}
setFieldValue={setFieldValue}
formValues={values}
setFieldTouched={setFieldTouched}
/>
)}
…
)
}}
</Form>
)
FormGenerator, в свою очередь получает поля формы и отрисовывает массив компонентов, в зависимости от типа поля формы
const composeForm = forms => {
const fields = getFileds(forms)
const formFields = fields?.reduce(
(acc, field) => {
const fieldId = getFieldId(field.id)
const value = data?.formValues?.customData[fieldId]
const touched = data?.touched?.customData && data?.touched?.customData[fieldId]
const fieldData = {
...field,
...data,
value,
touched,
fieldId,
}
if (inputHandlerDetector(fieldData)) {
return [...acc, inputHandlerDetector(fieldData)(fieldData)]
} else return acc
},
[])
return formFields
}
return composeForm(props.forms)
inputHandlerDetector возвращает компонент, который отрисовывает элемент формы
export const stringFieldHandler = data => {
const [error, setError] = useState('')
const { fieldId, id, matches, max, min, message, name, value, touched, setFieldValue, required, mask, disabled, type, typeName } = data
const validate = useCallback(() => {
if (!value?.length && required) {
setError(requiredFieldError)
addPersonnelActionErrorEvent({
[fieldId]: requiredFieldError
})
} else if (matches && !russianEnglishDotsNumbersCommasDashsParentheses.test(value)) {
setError(message ? message : 'Значение не соответствует формату')
addPersonnelActionErrorEvent({
[fieldId]: message ? message : 'Значение не соответствует формату'
})
} else if (max && value.length > max) {
setError(`Значение должно быть не более ${max} символов`)
addPersonnelActionErrorEvent({
[fieldId]: `Значение должно быть не более ${max} символов`
})
} else if (min && value.length < min) {
setError(`Значение должно быть не менее ${min} символов`)
addPersonnelActionErrorEvent({
[fieldId]: `Значение должно быть не менее ${min} символов`
})
} else if (id === 'custom/position' && !russianEnglishDotsNumbersSymbols.test(value)) {
setError(russianLettersError)
addPersonnelActionErrorEvent({
[fieldId]: russianLettersError
})
} else {
setError('')
addPersonnelActionErrorEvent({
[fieldId]: ''
})
}
}, [required, fieldId, value, id, matches, max, min, message])
useEffect(() => {
validate()
}, [value])
return (
<FieldFormik
key={fieldId}
id={`customData.${fieldId}`}
label={getFieldLabel(name, required)}
error={touched && error}
value={value}
mask={mask}
onChange={event => {
const { target } = event
let { value } = target
if (type === 'float') {
value = processNumber(value, precision)
} else if (type === 'int') {
value = processInteger(value)
}
setFieldValue(`customData.${fieldId}`, value)
}}
autoComplete="off"
placeholder={getPlaceholder(type, typeName)}
disabled={disabled}
/>
)
}
все работает, если валидацию вынести в родительский компонент, который содержит FormGenerator, но хочется валидировать поле в компоненте этого поля