React中props传递对象数组时子组件接收数据错乱排查
问题根因
你的代码有两个致命问题,直接导致数据错位:
Array.shift()是会直接修改原数组的可变方法:你把接口返回的二维数组直接存在state里,每次组件重渲染都会执行const keys = data.shift(),这行代码会直接删掉state数组的第一个元素。第一次渲染删的是表头行,第二次渲染就会把第一行商品数据当表头删,越往后错得越离谱。- 数据转换逻辑写在组件渲染顶层,每次渲染都会重复执行、重复修改原始state数据,形成恶性循环。你之前看到父组件打印的
dataObj结构正常,完全是浏览器控制台的对象懒求值特性给的错觉:控制台打印引用类型时不会立刻存下值,等你手动展开日志的时候,数组已经被多次shift()改得面目全非了,不是转换当下数据真的正常。
修复代码
不要在渲染阶段修改state、不要在渲染阶段反复做数据转换,直接在拿到接口返回的时候就把格式转好,再存到state里,修改后的父组件代码如下:
import React, { useState } from "react"; import Product from "./Product"; function Products() { // 直接存转换完成的对象数组,不需要存原始二维数组 const [productList, setProductList] = useState([]); const getData = () => { fetch( "https://sheets.googleapis.com/v4/spreadsheets/1DpaMUmqYxGUKnT9BL0uBuCZ6WJ8vd1CLAklqUvkcA8M/values/Sheet1?alt=json&key=AIzaSyD6o4v215zWtw-kOqGVeuLG50pE2QeRZTg", { method: "GET" } ) .then((response) => response.json()) .then((res) => { const rawValues = res.values; // 取第一行作为字段名,这里直接读索引,不会修改原数组 const keys = rawValues[0]; // 从第二行开始遍历,转换成对象结构 const formattedList = rawValues.slice(1).map(elem => ({ [keys[0]]: elem[0], [keys[1]]: elem[1], [keys[2]]: elem[2], [keys[3]]: elem[3], })); setProductList(formattedList); }); }; return ( <div> Hello, you're in the products page <button onClick={getData}>click me</button> {productList.map((prod) => ( <Product prod={prod} key={prod.id}/> ))} </div> ); } export default Products;
子组件不需要做任何修改,就能拿到结构正确的商品数据。
避坑提醒
- 操作React state的时候,绝对不要直接用
shift/splice/sort/reverse这类会原地修改原数组的方法,优先用slice/扩展运算符/map/filter这类返回新数组的方法,避免意外修改state导致不可预期的渲染问题。 - 调试打印引用类型(对象/数组)时,如果要确认打印瞬间的值,可以先转成JSON字符串再转回来做深拷贝,比如
console.log(JSON.parse(JSON.stringify(data))),避免被控制台的懒求值特性误导。
内容的提问来源于stack exchange,提问作者Favour Onyido
相关产品推荐
相关产品推荐

