useEffect内async函数的while循环中使用await不生效问题
问题根因
- 语法错误:原代码中
setProductsList([...productsList,item]])多写了一个右中括号,会直接导致语法解析失败。 - 同步代码优先执行:
callProduct是异步函数,调用后不会阻塞后续同步逻辑,console.log(productsList.length)运行时异步请求和 state 更新还未执行,拿到的始终是初始值 0。 - 闭包捕获旧 state:useEffect 依赖项为空数组,内部作用域捕获的
productsList永远是初始渲染时的空数组,每次执行setProductsList([...productsList, item])都是基于空数组拼接数据,最终只会保留最后一次循环拿到的 item,无法实现数据累加。 - 错误使用 await 修饰 setState:React 的 state 更新方法不返回 Promise,
await setProductsList()写法无效,不会等待 state 更新完成再执行后续逻辑。
修复方案
推荐先批量请求完所有数据再一次性更新 state,减少不必要的渲染次数,也能从根源避免闭包问题,代码示例如下:
useEffect(() => { // 标记组件挂载状态,避免组件卸载后更新state引发内存泄漏 let isMounted = true; async function callProduct(){ const tempList = []; let a = 5; while (a > 0) { const item = await contract.getProduct(a); tempList.push(item); a--; } if (isMounted) { setProductsList(tempList); // 需查看更新后的数据可在该处打印 console.log(tempList.length); } } callProduct(); // 清理函数 return () => { isMounted = false; }; }, []);
如果确实需要每次拿到单条数据就立即更新 state,可以使用 setState 的函数式更新写法,每次调用都能拿到最新的 state 值:
useEffect(() => { let isMounted = true; async function callProduct(){ let a = 5; while (a > 0) { const item = await contract.getProduct(a); if (isMounted) { // 函数式更新取上一次的state值,不受闭包影响 setProductsList(prevList => [...prevList, item]); } a--; } } callProduct(); return () => { isMounted = false; }; }, []);
额外说明
如果需要在 productsList 更新后执行对应逻辑,可以单独声明 useEffect 监听该 state 变化:
useEffect(() => { console.log(productsList.length); // 处理更新后的渲染、计算等逻辑 }, [productsList]);
内容的提问来源于stack exchange,提问作者Lee Alex
相关产品推荐
相关产品推荐

