React Hook Form提交后localStorage数据无法清除的问题排查
React Hook Form提交后无法清除localStorage表单数据
我用React Hook Form实现表单逻辑,通过localStorage成功实现了刷新页面保留输入值的功能,但提交表单后,调用localStorage.removeItem("formData")或localStorage.clear()都无法彻底清除存储的表单数据,输入框也没法完全清空——不管把清除代码放在提交完成后还是reset()之后都没用。
import { useForm, FormProvider } from "react-hook-form" import InputsWrapper from "./InputsWrapper" import Navbar from "../Navbar" import ChoosePackage from "../ChoosePackage" //@ts-ignore import { Packages } from "../../types" import axios from "axios" import { useEffect } from "react" interface FormData { name: string email: string phone: string city: string address: string contact_preference: string[] photos: Array<string | Blob> project_type: string project_level: string additional_info: string contractor: boolean | undefined package: Packages | undefined } type InquiryPayload = Omit<FormData, "photos"> & { photos: number[] } const defaultData = { name: "", email: "", phone: "", city: "", address: "", contact_preference: [], photos: undefined, project_type: "", project_stage: "", additional_info: "", contractor: undefined, package: undefined, } const Form: React.FC = () => { const FormMethods = useForm<FormData>({ defaultValues: defaultData }) const { handleSubmit, reset } = FormMethods useEffect(() => { const savedFormData = localStorage.getItem("formData") if (savedFormData) { const parsedFormData = JSON.parse(savedFormData) reset(parsedFormData) } }, []) useEffect(() => { const saveFormData = JSON.stringify(FormMethods.getValues()) localStorage.setItem("formData", saveFormData) }, [FormMethods.watch()]) const onFormSubmit = async (data: FormData) => { const token = "*********************" let formData = new FormData() Object.values(data.photos).forEach((photo: string | Blob) => formData.append("files", photo) ) try { const res = await axios({ method: "POST", url: "https://strapi-km.herokuapp.com/api/upload", data: formData, headers: { Authorization: `Bearer ${token}`, }, }) const photoIds: number[] = res.data.map((e: { id: number }) => e.id) let dataCopy: InquiryPayload = { ...data, photos: photoIds } const response = await axios({ method: "POST", url: "https://strapi-km.herokuapp.com/api/inquiries", data: { data: dataCopy }, headers: { Authorization: `Bearer ${token}`, }, }) window.alert("Form has been submitted !") console.log("Inquiry", response.data) } catch (error) { console.log(error) } localStorage.removeItem("formData") reset() } return ( <> <div className="bg-gray-50"> <Navbar /> <FormProvider {...FormMethods}> <form onSubmit={handleSubmit(onFormSubmit)}> <div> <ChoosePackage /> <InputsWrapper /> <div className="mx-10"> <button className="transition-colors duration-300 w-full mb-5 tracking-widest text-2xl border border-black text-gray-50 p-2 hover:bg-indigo-100 hover:text-indigo-900 bg-indigo-800" type="submit" > SUBMIT </button> </div> </div> </form> </FormProvider> </div> </> ) } export default Form
问题原因
核心问题出在监听表单变化的useEffect上:当你调用reset()后,表单值会变回defaultData,这会触发FormMethods.watch()的更新,导致该useEffect再次执行,把重置后的表单值(即使是空或undefined,依然会被序列化为JSON)重新存入localStorage,看起来就像清除操作没有生效。
解决方案
方案1:判断表单状态,仅保存非初始值
调整监听的useEffect,对比当前表单值和默认值,只有当表单非初始状态时才存入localStorage,否则清除存储:
useEffect(() => { const currentValues = FormMethods.getValues(); // 对比当前值与默认值,判断是否为初始状态 const isDefault = Object.entries(defaultData).every(([key, value]) => { const currentVal = currentValues[key as keyof FormData]; // 处理数组类型的字段对比 if (Array.isArray(value)) { return Array.isArray(currentVal) && currentVal.length === value.length; } return currentVal === value; }); if (!isDefault) { const saveFormData = JSON.stringify(currentValues); localStorage.setItem("formData", saveFormData); } else { localStorage.removeItem("formData"); } }, [FormMethods.watch()]);
方案2:用状态标记提交重置阶段,跳过保存
添加一个状态标记当前是否处于提交后的重置阶段,避免此时写入localStorage:
import { useState } from "react"; // ... 其他代码 ... const Form: React.FC = () => { const [isSubmittingReset, setIsSubmittingReset] = useState(false); const FormMethods = useForm<FormData>({ defaultValues: defaultData }) const { handleSubmit, reset } = FormMethods // ... 初始化的useEffect ... useEffect(() => { if (isSubmittingReset) return; const saveFormData = JSON.stringify(FormMethods.getValues()) localStorage.setItem("formData", saveFormData) }, [FormMethods.watch(), isSubmittingReset]) const onFormSubmit = async (data: FormData) => { // ... 原有提交逻辑 ... setIsSubmittingReset(true); reset(); localStorage.removeItem("formData"); // 延迟重置状态,确保表单更新完成后恢复正常保存逻辑 setTimeout(() => setIsSubmittingReset(false), 0); } // ... 返回JSX ... }
内容的提问来源于stack exchange,提问作者DrSpliff
相关产品推荐
相关产品推荐

