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

React页面重载后LocalStorage存在键但值丢失问题

问题原因及解决方案

核心问题

你把localStorage.setItem("data", JSON.stringify(formValues))直接写在了JSX的渲染分支里,这会导致每次组件渲染(包括页面重载后)都会执行这行代码。页面重载时,formValues初始值是空对象{username:"", password: ""},所以会把LocalStorage里原来的有效数据覆盖成空值,最终表现为键存在但值丢失。

另外,isSubmit的初始状态判断会在页面重载时,如果LocalStorage有数据就设为true,直接进入成功渲染分支,触发上述的覆盖操作。

修复步骤

  1. 将LocalStorage存储逻辑移到表单提交验证通过后
    修改handleSubmit函数,只有当验证无错误时,再存入LocalStorage并设置isSubmit为true:

    const handleSubmit = (e) => {
      e.preventDefault();
      const errors = validate(formValues);
      setFormErrors(errors);
      // 验证通过才执行存储和提交状态设置
      if (Object.keys(errors).length === 0) {
        localStorage.setItem("data", JSON.stringify(formValues));
        setIsSubmit(true);
      }
    };
    
  2. 从LocalStorage初始化表单数据(可选,优化体验)
    页面重载时,从LocalStorage读取已存储的数据来初始化formValues,避免表单回到空状态:

    const initialValues = JSON.parse(localStorage.getItem("data")) || { username:"", password: "" };
    const [formValues, setFormValues] = useState(initialValues);
    
  3. 移除JSX中的存储代码
    删掉成功分支里的{localStorage.setItem("data", JSON.stringify(formValues))},这行代码是问题根源。

修复后的完整代码

import { useState } from "react";

function App() {
  // 从LocalStorage读取初始值,没有则用空对象
  const initialValues = JSON.parse(localStorage.getItem("data")) || { username:"", password: "" };
  const [formValues, setFormValues] = useState(initialValues);
  const [formErrors, setFormErrors] = useState({});
  const [isSubmit, setIsSubmit] = useState(
    JSON.parse(localStorage.getItem("data")) ? true : false
  );

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormValues({ ...formValues, [name]: value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const errors = validate(formValues);
    setFormErrors(errors);
    // 验证通过才存储并设置提交状态
    if (Object.keys(errors).length === 0) {
      localStorage.setItem("data", JSON.stringify(formValues));
      setIsSubmit(true);
    }
  };

  const validate = (values) => {
    const errors = {};
    if (!values.username) {
      errors.username = "Username is required!";
    }

    if (!values.password) {
      errors.password = "Password is required";
    } else if (values.password.length < 4) {
      errors.password = "Password must be more than 4 characters";
    } else if (values.password.length > 8) {
      errors.password = "Password cannot exceed more than 10 characters";
    }
    return errors;
  };
  
  const logout = () => {
    setIsSubmit(false);
    localStorage.clear();
    // 登出后重置表单值
    setFormValues({ username:"", password: "" });
  };

  return (
    <div className="container">
      {Object.keys(formErrors).length === 0 && isSubmit ? (
        <>
          <div>
            hello {JSON.parse(localStorage.getItem("data")).username} ,Signed
            in successfully
          </div>
          <button onClick={logout}>LOG OUT</button>
        </>
      ) : (
        <form onSubmit={handleSubmit}>
          <div>
            <div>
              <label>Username</label>
              <input
                type="text"
                name="username"
                placeholder="Username"
                value={formValues.username}
                onChange={handleChange}
              />
            </div>
            <p>{formErrors.username}</p>
            <div>
              <label>Password</label>
              <input
                type="password"
                name="password"
                placeholder="Password"
                value={formValues.password}
                onChange={handleChange}
              />
            </div>
            <p>{formErrors.password}</p>
            <button>Submit</button>
          </div>
        </form>
      )}
    </div>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者kiran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:25:25