You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:00:53