React状态已更新但JSX不渲染问题排查求助
问题:点击按钮后JSX未更新渲染数据,修改代码保存后却正常显示
尝试展示包含产品及其产品编号的表格,通过console.log查看state发现数据符合预期,但点击“GET Product numbers”按钮时JSX并未更新渲染数据。不过当修改代码并保存后,数据能正常显示在表格中,希望指出问题所在。
import { useState } from "react"; import "./App.css"; function Temp() { const [products, setproducts] = useState(); const [productnumbers, setproductnumbers] = useState([]); var final = []; const productsArray = products?.split(",").map(function (item) { return item.trim(); }); async function fetchproducts() { productsArray.forEach(async (e, i) => { await fetch("API URL", productsArray) .then((res) => res.json()) .then((json) => { let q = json.styleId.toString(); final.splice(i, 0, { key: e, value: q }); return; }) .catch((ERR) => { return ERR; }); }); setproducts(""); setproductnumbers(final); return; } var unique = productnumbers.filter( (ele, ind) => ind === productnumbers.findIndex( (elem) => elem.key === ele.key && elem.value === ele.value ) ); console.log("new-state", productnumbers); return ( <div> <header className="App-header"> <div className="wrapper"> <textarea value={products} onChange={(e) => setproducts(e.target.value)} placeholder='Enter products seperated with ","' name="skus" id="gm-skus" cols="30" rows="10" ></textarea>{" "} <button onClick={fetchproducts}>GET Product numbers</button> </div> <div className="tableContainer"> <table width="100%"> <tr> <td>Products</td> <td>Product numbers</td> </tr> {unique.map((each, i) => { return ( <tr key={i}> <td>{each.key}</td> <td>{each.value}</td> </tr> ); })} </table> </div> </header> </div> ); } export default Temp;
问题根源及解决方案
1. 异步循环未等待请求完成
forEach中使用async/await不会等待所有异步请求执行完毕,你在循环结束后立刻调用setproductnumbers(final),此时所有API请求还没返回,final仍是空数组。等请求返回后修改final,但这时候已经执行过状态更新,且final是普通变量,修改它不会触发组件重新渲染。
2. 错误的fetch参数传递
原代码中fetch("API URL", productsArray)的第二个参数不符合fetch API规范,fetch的第二个参数应为请求配置对象(如method、headers、body等),而非要传递的数组数据,需根据API实际要求调整。
修正后的代码
import { useState } from "react"; import "./App.css"; function Temp() { const [products, setproducts] = useState(); const [productnumbers, setproductnumbers] = useState([]); const productsArray = products?.split(",").map(item => item.trim()); async function fetchproducts() { if (!productsArray || productsArray.length === 0) return; // 用Promise.all等待所有异步请求完成 const requests = productsArray.map(async (product) => { try { // 根据实际API需求调整fetch参数 const res = await fetch("API URL", { method: "POST", // 假设是POST请求 headers: { "Content-Type": "application/json" }, body: JSON.stringify({ product }) }); const json = await res.json(); return { key: product, value: json.styleId.toString() }; } catch (err) { console.error(`获取${product}编号失败:`, err); return { key: product, value: "获取失败" }; } }); const finalData = await Promise.all(requests); setproducts(""); setproductnumbers(finalData); } const unique = productnumbers.filter( (ele, ind) => ind === productnumbers.findIndex( (elem) => elem.key === ele.key && elem.value === ele.value ) ); console.log("new-state", productnumbers); return ( <div> <header className="App-header"> <div className="wrapper"> <textarea value={products} onChange={(e) => setproducts(e.target.value)} placeholder='Enter products seperated with ","' name="skus" id="gm-skus" cols="30" rows="10" ></textarea>{" "} <button onClick={fetchproducts}>GET Product numbers</button> </div> <div className="tableContainer"> <table width="100%"> <tr> <td>Products</td> <td>Product numbers</td> </tr> {unique.map((each, i) => ( <tr key={i}> <td>{each.key}</td> <td>{each.value}</td> </tr> ))} </table> </div> </header> </div> ); } export default Temp;
关键优化点
- 使用
Promise.all统一等待所有API请求完成,确保获取到完整数据后再更新状态 - 修正fetch的参数传递,符合API调用规范
- 移除组件内的普通变量
final,直接通过异步请求结果生成新数组,保证状态更新时传递新的数组引用,触发React重新渲染
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

