React数组重映射结果为空数组及循环次数异常问题排查
问题分析与解决方案
问题1:控制台输出空数组
React状态更新是异步的,且useEffect回调中捕获的series是组件初始渲染时的状态值(空数组)。每次调用setSeries后,series不会立即更新,因此console.log(series)打印的始终是初始的空数组。
问题2:循环执行6次而非3次
这是开发环境下React严格模式导致的:严格模式会重复执行useEffect等钩子函数(执行两次),用来检测代码中的潜在问题。你的data.map本身会遍历3次,3×2就出现了6次循环,生产环境下不会有这个重复执行的情况。
额外问题:状态更新写法错误
原代码中setSeries(...series, { product: rec[0], sales: Number(rec[1]) })的写法不正确,setSeries需要接收完整的新数组,而不是展开数组元素。这种写法会导致状态被替换成单个对象而非数组,后续更新还会覆盖之前的状态。
修正方案
方案1:一次性处理所有数据后更新状态(推荐)
先将data转换为目标格式的数组,再一次性设置状态,避免多次触发组件渲染:
import React from "react"; import "./style.css"; export default function App() { const data = [ { "record": [["Conferencing", "1", "8"]] }, { "record": [["Expenses", "514", "6"]] }, { "record": [["Mobiles", "717", "2"]] } ]; const [series, setSeries] = React.useState([]); React.useEffect(() => { // 一次性转换所有数据 const newSeries = data.map(o => { const rec = o.record[0]; return { product: rec[0], sales: Number(rec[1]) }; }); setSeries(newSeries); console.log(newSeries); // 直接打印转换后的数组 }, []); return ( <div> <h1>Hello StackBlitz!</h1> </div> ); }
方案2:使用函数式更新(适合需要逐步更新的场景)
如果需要逐步添加元素,使用setSeries的函数式更新,确保每次获取到最新的状态:
import React from "react"; import "./style.css"; export default function App() { const data = [ { "record": [["Conferencing", "1", "8"]] }, { "record": [["Expenses", "514", "6"]] }, { "record": [["Mobiles", "717", "2"]] } ]; const [series, setSeries] = React.useState([]); React.useEffect(() => { data.forEach(o => { const rec = o.record[0]; // 使用函数式更新,prev是最新的状态数组 setSeries(prev => [...prev, { product: rec[0], sales: Number(rec[1]) }]); }); // 若要查看最终状态,可在另一个useEffect中监听series变化 // React.useEffect(() => console.log(series), [series]); }, []); return ( <div> <h1>Hello StackBlitz!</h1> </div> ); }
内容的提问来源于stack exchange,提问作者Black
相关产品推荐
相关产品推荐

