React Native第二个useEffect未获取首个useEffect的ref更新值
问题根源
同一轮渲染周期内,useEffect确实是严格按照代码声明的先后顺序执行的,你遇到的问题和执行顺序无关,核心原因有两点:
- 依赖为
[]的useEffect只会在组件首次挂载完成后执行唯一一次,后续不会再主动触发。 - 你代码注释中标注了
_ref.current = cb是异步逻辑:第一个useEffect虽然先执行,但如果给ref赋值的操作被包裹在异步回调中(比如接口请求、Promise.then、setTimeout等),那第一个effect执行时只会发起异步任务,不会等待异步任务完成就会继续执行后续逻辑。等第二个useEffect同步执行打印时,异步赋值逻辑还没运行,_ref.current还是初始化时的空对象{},读取a/b/c属性自然全是undefined。
常见误区提醒:useEffect的执行顺序只针对同步执行的effect回调本身,回调内部的异步逻辑执行时机由JS事件循环决定,和effect声明顺序没有关系,不存在“写在前面的effect所有逻辑都跑完才会执行后面effect”的规则。
解决方案
根据业务场景选择对应实现即可,不要用加延迟、轮询ref这类不稳定的hack方案:
方案1:值同步生成时,用state代替ref做依赖追踪
如果cb的值不需要依赖异步结果,不要用ref存储渲染/逻辑依赖的值,ref的修改不会触发组件重渲染,也不会触发useEffect重新执行。直接将值存在state中,把state加入第二个effect的依赖数组即可:
export default MyComp = ({ navigation, route}) => { const _ref = useRef({}); const [cb, setCb] = useState({}); // 1st useEffect useEffect(()=> { const newCb = {a:1, b:2, c:3}; _ref.current = newCb; setCb(newCb); }, [var1,var2]); // 2nd useEffect useEffect(()=>{ // 增加判空逻辑,跳过初始空值的情况 if (cb.a !== undefined) { console.log(`${cb.a} ${cb.b}, ${cb.c}`); } },[cb]); }
方案2:值异步生成时,直接在赋值完成节点执行后续逻辑
如果cb是异步请求/操作后才能拿到的值,不需要单独拆分空依赖的useEffect,直接在异步赋值完成的回调里执行打印逻辑即可,从根源上避免时序问题:
useEffect(()=> { // 模拟异步获取值的逻辑 someAsyncOperation().then(res => { const cb = {a:1, b:2, c:3}; _ref.current = cb; // 赋值完成后直接执行后续逻辑 console.log(`${_ref.current.a} ${_ref.current.b}, ${_ref.current.c}`); }) }, [var1,var2]);
方案3:需要在多个场景触发打印逻辑时,抽离公共方法
如果打印逻辑需要在多个时机触发,可以把逻辑抽成独立函数,在赋值完成、其他依赖变化的节点分别调用,不要依赖空数组effect去等ref的异步赋值。
内容的提问来源于stack exchange,提问作者user938363
相关产品推荐
相关产品推荐

