如何使用react-hook-form和useContext实现多步骤表单值存储?求助排查
Hey there! Let's figure out why your multi-step form with react-hook-form and Context is acting up—sounds like the state sync between the two is the main culprit. Here's what's likely going wrong and how to fix it:
1. Context isn't getting updated in real-time
Right now, it sounds like you're only pushing form values to Context when you hit SUBMIT, which is why you see an update then but no data stored before that. React-hook-form manages its own internal state, so you need to explicitly sync those changes to your Context as the user types.
- Fix: Use react-hook-form's
watchfunction to track value changes and update Context immediately:import { useForm, watch } from 'react-hook-form'; import { useFormContext } from './your-form-context-file'; function PersonalInfoStep() { const { register, control } = useForm(); const { updateFormData } = useFormContext(); const currentFormValues = watch(control); // Tracks all form field changes // Sync new values to Context whenever they change useEffect(() => { updateFormData(currentFormValues); }, [currentFormValues, updateFormData]); return ( <div> <input {...register('firstName', { required: true })} placeholder="First Name" /> <input {...register('lastName', { required: true })} placeholder="Last Name" /> </div> ); }
2. Context state is being overwritten instead of merged
If you're replacing the entire Context state object when updating, you'll lose data from previous steps. For example, if Step 1 saves name data and Step 2 saves contact info, overwriting the state would erase the name when you enter contact details.
- Fix: Merge new values with existing Context state using the spread operator:
import { createContext, useState, useContext } from 'react'; const FormContext = createContext(); export function FormProvider({ children }) { const [formData, setFormData] = useState({}); const updateFormData = (newValues) => { // Spread existing state and merge new values setFormData(prevState => ({ ...prevState, ...newValues })); }; return ( <FormContext.Provider value={{ formData, updateFormData }}> {children} </FormContext.Provider> ); } export const useFormContext = () => useContext(FormContext);
3. React-hook-form isn't initialized with Context data
When switching between steps, react-hook-form might reset its internal state unless you initialize it with the data already stored in Context. This can make it seem like Context has no data until you submit.
- Fix: Pass
defaultValuestouseFormusing your Context data:import { useForm } from 'react-hook-form'; import { useFormContext } from './your-form-context-file'; function ContactInfoStep() { const { formData } = useFormContext(); const { register } = useForm({ defaultValues: formData // Load existing Context data into the form }); return ( <div> <input {...register('email', { required: true, pattern: /^\S+@\S+$/i })} placeholder="Email" /> <input {...register('phone', { required: true })} placeholder="Phone Number" /> </div> ); }
4. Invalid state on submit
If you're seeing values update but the form state is marked invalid when you submit, it's probably because you're not using react-hook-form's built-in submission handler correctly, or validation isn't applied to all fields across steps.
- Fix: Use
handleSubmitto manage submission, and ensure all fields have proper validation rules. For multi-step forms, you can also trigger validation for all fields on final submit:import { useForm, handleSubmit } from 'react-hook-form'; import { useFormContext } from './your-form-context-file'; function FinalSubmitStep() { const { formData } = useFormContext(); const { register, handleSubmit, formState: { errors } } = useForm({ defaultValues: formData }); const onSubmit = (submittedData) => { // This should include all data from every step, synced via Context console.log('Full Submission Data:', submittedData); // Send to API or process here }; return ( <form onSubmit={handleSubmit(onSubmit)}> {/* Optional: Add a confirmation check */} <label> <input {...register('confirm', { required: 'Please confirm to submit' })} type="checkbox" /> I confirm all details are correct </label> {errors.confirm && <p style={{ color: 'red' }}>{errors.confirm.message}</p>} <button type="submit">SUBMIT</button> </form> ); }
- Make sure every step component is wrapped inside your
FormProvider—if not, they won't have access to the Context. - Double-check that all input fields have the
registerfunction applied—any field without it won't be tracked by react-hook-form. - Ensure your Context's
updateFormDatafunction isn't accidentally resetting the state (nosetFormData({})without spreading previous state!).
Since you mentioned the UI is rough but the core form behavior is otherwise on track, fixing these sync issues should get your Context populated correctly and resolve the invalid state on submit.
内容的提问来源于stack exchange,提问作者karo-s

