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

useState/useMemo浏览器刷新后值重置,学生成绩总分计算异常

问题:浏览器刷新后成绩总分重置为0,useEffect/useMemo失效但普通变量正常

我在计算学生考试成绩表格的总分时,保存修改能得到正确结果,但浏览器刷新后数值就变成0。试过用useEffect()和useMemo()钩子都没用,但用普通变量(不用useState())的话,刷新后数值能保留。

相关代码(不工作的实现)

const englishSubmitted = JSON.parse(
  localStorage.getItem("englishSubmitted") as string
);
const [englishResult, setEnglishResult] = useState<
  { [key: string]: string }[]
>([]);


useEffect(() => {
  if (englishSubmitted) {
    setEnglishResult(
      JSON.parse(localStorage.getItem("englishAnswers") as string)
    );
  }
},[])


// 这个写法不生效
useEffect(() => {
  const value = englishResult.reduce((acc, current) => {
    acc += parseInt(current.marks);
    return acc;
  }, 0);
  setEnglishMarks(value);
}, []);

// 这个写法也不生效
useMemo(() => {
  const value = englishResult.reduce((acc, current) => {
    acc += parseInt(current.marks);
    return acc;
  }, 0);
  setEnglishMarks(value);
}, []);

即使给依赖数组添加值也解决不了问题。

可正常工作的实现(普通变量)

const value = englishResult.reduce((acc, current) => {
  acc += parseInt(current.marks);
  return acc;
}, 0);

问题原因

  1. 钩子执行时机不对:
    第一个useEffect是在组件挂载后才去加载localStorage里的englishAnswers并更新englishResult。但你那两个计算总分的useEffect/useMemo依赖数组是空的,只会在组件挂载时执行一次——这时候englishResult还是初始的空数组,算出来的总分自然是0,之后也不会因为englishResult更新而重新计算。
  2. 普通变量的渲染特性:
    普通变量会在组件每次渲染时重新计算,当第一个useEffect更新englishResult后,组件会触发重新渲染,这时候普通变量会用更新后的englishResult重新计算总分,所以刷新后能得到正确值。

解决方案

方案1:给计算总分的useEffect加正确依赖

让计算逻辑监听englishResult的变化,每次englishResult更新时重新计算总分:

useEffect(() => {
  const value = englishResult.reduce((acc, current) => {
    // 加个||0防止parseInt转换失败导致NaN
    acc += parseInt(current.marks) || 0;
    return acc;
  }, 0);
  setEnglishMarks(value);
}, [englishResult]); // 这里添加englishResult作为依赖

方案2:用useMemo缓存计算结果(无需额外state)

如果不需要把总分存在单独的state里,直接用useMemo缓存计算结果即可,同样依赖englishResult:

const englishMarks = useMemo(() => {
  return englishResult.reduce((acc, current) => {
    acc += parseInt(current.marks) || 0;
    return acc;
  }, 0);
}, [englishResult]);

方案3:初始化时直接加载数据并计算

可以在初始化englishResult的时候就从localStorage取数据,同时计算总分,避免钩子执行顺序的问题:

// 初始化时直接加载数据
const initialEnglishResult = englishSubmitted 
  ? JSON.parse(localStorage.getItem("englishAnswers") as string) 
  : [];
const [englishResult, setEnglishResult] = useState<{ [key: string]: string }[]>(initialEnglishResult);

// 直接计算总分,组件渲染时自动更新
const englishMarks = initialEnglishResult.reduce((acc, current) => {
  acc += parseInt(current.marks) || 0;
  return acc;
}, 0);

注意:如果之后englishResult会被动态修改,方案3需要配合方案1或2来监听变化重新计算。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:45:18