React Native useState计数器无法正常累加 无法触发setLoading问题
问题根因与修复方案
核心问题
- 闭包陷阱:useEffect依赖数组为空,仅在组件挂载时执行一次,作用域内捕获的
loopCount永远是初始值'1',每次setLoopCount(loopCount+1)都是基于同一个初始值计算,无法正常累加。只有组件刷新后effect重新执行才会拿到最新的state值,这就是仅按CTRL+S刷新时计数器才会自增1的原因。 - 类型错误:
loopCount初始值为字符串类型'1',执行+1操作时会触发字符串拼接(得到'11'而非数字2),和数字类型的data.length比对逻辑完全失效。 - state异步更新:调用
setLoopCount后立即读取loopCount拿到的还是更新前的旧值,if(loopCount >= data.length)的判断逻辑完全无效。 - 异步操作无等待:
AsyncStorage.getItem是异步方法,forEach不会等待回调执行就会跑完所有循环,此时大部分异步操作还未返回,loopCount还未完成累加,判断加载结束的时机完全错误。
修复后代码
// 初始值改为数字类型,从0开始计数 const [loopCount, setLoopCount] = useState(0); const [isLoading, setLoading] = useState(true); // 监听loopCount变化,达到阈值时关闭loading useEffect(() => { if(loopCount >= data.length){ setLoading(false); } }, [loopCount, data.length]) useEffect(() => { const getPackages = async () => { try { const offerings = await Purchases.getOfferings(); if (offerings.current !== null) { // 收集所有异步操作 const promises = []; data.forEach((category, index) => { if(category.entitlement_id){ // 异步操作加入队列 const promise = AsyncStorage.getItem(category.entitlement_id).then((value) => { // 函数式更新,基于上一次state值计算,规避闭包问题 setLoopCount(prev => prev + 1); }); promises.push(promise); }else{ setLoopCount(prev => prev + 1); } }) // 等待所有异步操作执行完成 await Promise.all(promises); }else{ console.log("No offerings found"); setLoading(false); } } catch (e) { console.log("Error => " + e); // 异常场景关闭loading,避免无限加载 setLoading(false); } } getPackages(); }, [])
补充说明
如果不需要用loopCount做其他渲染逻辑,可直接删除该state,在await Promise.all(promises)执行完成后直接调用setLoading(false)即可,代码更简洁。
内容的提问来源于stack exchange,提问作者Noman Ali
相关产品推荐
相关产品推荐

