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

setState调用顺序是否会导致Undefined is not an object (evaluating '_ref5.x')报错?

报错根本原因

你遇到的问题核心是React 17及更早版本中,await 这类异步回调里的 setState 不会走批量更新逻辑,每调用一次 setState 就会立刻触发一次组件重渲染,再加上你代码里的状态依赖逻辑,就出现了顺序影响报错的情况。
你看到的_ref5是代码编译打包后的变量别名,对应的就是你代码里某个要访问.x属性的对象,报错就是因为这个对象在中间渲染态是undefined:

  • 原来的执行顺序(先setArr,后setTerminal):
    1. 调用setArr(data)后立刻触发第一次重渲染,此时对应日期的价格数组已经更新为新的data,但terminal还是旧值。如果你的JSX渲染逻辑、或者其他依赖这两个状态的useEffect里,有代码需要同时用到两个状态的最新值,就会出现数据不匹配,刚好访问到了undefined对象的.x属性,直接抛错。
    2. 第一次重渲染完成后才会执行setTerminal,触发第二次重渲染,此时两个状态才同步为有效值,但第一次的报错已经抛出来了。
  • 调整顺序后(先setTerminal,后setArr):
    两次重渲染的中间态没有出现逻辑不兼容的状态组合,所以不会触发报错。但这只是临时绕开了问题,没有解决根本的状态不同步漏洞。

代码优化建议

1. 把关联的状态更新合并为单次重渲染

不管用哪个版本的React,都建议把相关联的状态更新合并,避免出现中间态:

  • 用React 18的话默认所有更新都会批量处理,不需要额外操作,不管顺序怎么写都只会触发一次重渲染;
  • 用React 17及更早版本的话,可以用官方提供的批量更新方法包裹两次setState:
// React Native 里从'react-native'导入即可
import { unstable_batchedUpdates } from 'react-native';

// 调用的时候直接包裹即可
unstable_batchedUpdates(() => {
  setArr(data);
  setTerminal(data[data.length - 1].val);
})

这样两次更新会合并成一次重渲染,两个状态同时更新,不管顺序怎么写都不会出现中间态不匹配的问题。

2. 删掉冗余的重复状态定义

你现在定义了5个结构完全相同的价格数组状态,还要单独维护dayToArray映射,不仅代码冗余,还有快照问题:dayToArray写在组件顶层,每次重渲染都会重新创建,里面存的状态值都是当前渲染周期的快照,永远拿不到最新值,后续很容易踩坑。
可以直接把所有日期的价格存在同一个状态里:

// 一个状态存所有天数的价格
const [prices, setPrices] = useState({
  1: [], 2: [], 3: [], 4: [], 5: []
});
const [terminal, setTerminal] = useState('0');

要用对应天数的价格直接取prices[day]就行,更新的时候也只要操作这个对象,不用维护5个单独的state和映射关系,代码简洁很多。

3. 修复疑似笔误和空值问题

你原有代码的缓存判断分支里写的是arrRef[arr.length - 1].val,看起来大概率是笔误,应该是要取arr[arr.length - 1].val?如果arrRef是你单独定义的ref,要注意每次价格数组更新的时候同步更新ref的current值,不然会出现取值不准的问题。
另外建议所有取值的地方都加上可选链做兼容,比如data?.[data.length - 1]?.val,避免API返回空数组或者异常值的时候直接抛错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 18:06:03