Синхронизация defaultValues в React Hook Form с react-query
При разработке на React разработчики часто комбинируют react-hook-form и react-query. Возникает задача: как правильно обновлять поля формы, когда серверные данные меняются (например, при refetchOnWindowFocus или после успешного сохранения). Рассмотрим типовую реализацию и ответим на ключевые вопросы.
Проблема: два сценария обновления defaultValues
В вашем компоненте AgreementForm используется useForm с defaultValues, полученными из запроса react-query. Есть два сценария:
- Фоновое обновление (refetchOnWindowFocus) - нужно частично синхронизировать поля, которые пользователь не трогал.
- Успешный submit - нужно полностью сбросить форму до новых данных с сервера.
Нужна ли синхронизация при фоновом обновлении?
Да, в большинстве случаев синхронизация нужна. Если пользователь не редактировал поля, а серверные данные изменились (например, другой пользователь обновил договор), форма должна отображать актуальную информацию. Однако следует избегать сброса изменённых полей - это может вызвать путаницу. Используйте reset(defaultValues, { keepDirtyValues: true }).
Реализация двух кейсов в одной форме
Для одновременной поддержки обоих сценариев можно использовать useEffect с разными условиями. Пример:
const { reset, formState: { isSubmitting, isSubmitSuccessful } } = useForm({
defaultValues: defaultValues ?? schema.getDefault(),
});
// Сценарий 1: фоновое обновление
useEffect(() => {
if (!defaultValues || isSubmitSuccessful) return;
reset(defaultValues, {
keepDirtyValues: true,
keepErrors: true,
keepTouched: true,
keepIsSubmitted: true,
keepSubmitCount: true,
keepIsValid: true,
});
}, [reset, defaultValues, isSubmitSuccessful]);
// Сценарий 2: после успешного submit
useEffect(() => {
if (!isSubmitSuccessful || !defaultValues) return;
reset(defaultValues); // полный сброс
}, [reset, defaultValues, isSubmitSuccessful]);Важные детали
- Флаг isSubmitSuccessful помогает разделить логику: после submit сбрасываем всё, иначе - только нетронутые поля.
- keepDirtyValues: true защищает изменённые пользователем поля от перезаписи при фоновом обновлении.
- Не забудьте сбросить
isSubmitSuccessfulпосле обработки, чтобы избежать повторных срабатываний.
Альтернативные подходы
Можно использовать watch для отслеживания изменений или передавать key в компонент формы для полного пересоздания, но это менее гибко. Рекомендованный способ - через reset с конфигурацией.