React子组件传参异常:所有子组件接收同一最终值问题排查
问题原因
这是典型的JavaScript闭包陷阱:你在forEach循环里声明的position是一个全局(相对于循环)变量,循环里的回调函数捕获的是这个变量的引用,而非每次循环时的数值快照。
因为React的setState是异步操作,当这些回调实际执行时,position已经完成了所有递增操作,最终变成了40。所有<VisitedCountry>组件的position属性都会指向这个最终值,导致子组件拿到的都是40。
解决方案
方案1:使用forEach的索引参数(最直接)
利用forEach的第二个参数(循环索引,从0开始)生成position,索引是每次循环的固定值,不会被后续修改影响:
data.countries.forEach((el, index) => { const currentPosition = index + 1; // 索引从0开始,加1得到1-40的序号 setCountryList(tmpCountry => [...tmpCountry, <VisitedCountry position={currentPosition} />]); });
方案2:用map替代forEach(React推荐写法)
React中处理数组渲染更推荐用map,它直接返回元素数组,还能避免多次调用setState的问题,同时记得给列表元素加唯一key:
// 一次性生成所有组件,再更新state const newCountryComponents = data.countries.map((el, index) => { // 优先用国家的唯一标识作为key(比如el.id、el.countryCode),没有的话再用index return <VisitedCountry key={index} position={index + 1} />; }); setCountryList(newCountryComponents);
方案3:捕获每次循环的position快照
如果坚持用forEach,可以在循环内部用const捕获当前position的数值快照,避免闭包引用同一个变量:
let position = 1; data.countries.forEach(el => { const currentPos = position; // 捕获当前循环的position值 setCountryList(tmpCountry => [...tmpCountry, <VisitedCountry position={currentPos} />]); position++; });
内容的提问来源于stack exchange,提问作者Pizzaboy
相关产品推荐
相关产品推荐

