React问题:父组件传递的Props与子组件接收的不一致
解决React组件Props传递不一致的问题
咱们来拆解一下你遇到的这个props值不一致的问题,大概率是两个常见的React开发陷阱导致的,一步步排查解决:
核心原因猜测
从你的描述来看,父组件里的userPrimaryGrid.array和子组件接收的props.board.array不一样,而且randomPlaceShip没有重复触发日志,最可能的两个原因是:
createGameboard的数组是共享引用:如果你的createGameboard函数里的array是定义在函数外面的全局变量,那所有创建的gameboard实例都会共用同一个数组——你修改一个实例的数组,其他实例的数组也会跟着变,甚至父组件重新渲染时创建新实例会覆盖原数据。- 函数组件重复执行导致重复创建实例:React函数组件每次渲染都会从头跑一遍所有代码,如果你没缓存
userPrimaryGrid,父组件只要一重新渲染,就会再次创建新的gameboard并调用randomPlaceShip,子组件拿到的就是新实例,而你看到的父组件console.log是第一次创建的结果。
分步解决方法
第一步:修复createGameboard,让每个实例有独立的数组
先检查你的createGameboard实现,必须在函数内部创建每个实例专属的array,不能用外部共享变量。修改后的代码示例如下:
const createGameboard = (type) => { // 每个gameboard实例都创建自己的10x10数组,互不干扰 const array = Array.from({ length: 10 }, () => Array(10).fill(false)); const randomPlaceShip = (ship) => { // 这里操作的就是当前实例的专属array let direction = ''; let randomDirection = _.random(0, 1); let x = _.random(0, 9); let y = _.random(0, 9); randomDirection === 0 ? (direction = 'horizontal') : (direction = 'vertical'); console.log(x, y, direction); let position = false; while (position === false) { if (direction === 'horizontal') { if (y > 10 - ship.length || array[x][y] !== false) { console.log(`cant place ship in ${x},${y}`); randomDirection = _.random(0, 1); x = _.random(0, 9); y = _.random(0, 9); randomDirection === 0 ? (direction = 'horizontal') : (direction = 'vertical'); console.log(x, y, direction); } else { for (let i = 0; i < ship.length; i++) { ship.hitPoints[i].x = x; ship.hitPoints[i].y = i + y; array[x][i + y] = ship.hitPoints[i]; position = true; } } } if (direction === 'vertical') { if (x > 10 - ship.length || array[x][y] !== false) { console.log(`cant place ship in ${x},${y}`); randomDirection = _.random(0, 1); x = _.random(0, 9); y = _.random(0, 9); randomDirection === 0 ? (direction = 'horizontal') : (direction = 'vertical'); console.log(x, y, direction); } else { for (let i = 0; i < ship.length; i++) { ship.hitPoints[i].x = i + x; ship.hitPoints[i].y = y; array[i + x][y] = ship.hitPoints[i]; position = true; } } } } console.log(x, y, direction); }; return { type, array, randomPlaceShip }; };
第二步:用useMemo缓存gameboard实例,避免重复创建
React函数组件每次渲染都会重新执行内部代码,所以我们需要用useMemo把创建好的gameboard缓存起来,确保只在组件挂载时创建一次:
import { useMemo } from 'react'; const Main = () => { const carrier = createShip(5); // 用useMemo缓存,依赖项为空数组,只会执行一次 const userPrimaryGrid = useMemo(() => { const grid = createGameboard('primary'); grid.randomPlaceShip(carrier); console.log('父组件的grid array:', grid.array); return grid; }, []); // 同样缓存其他gameboard实例 const userTrackingGrid = useMemo(() => createGameboard('tracking'), []); const computerTrackingGrid = useMemo(() => createGameboard('tracking'), []); return ( <div className="main"> <Gameboard type={'primary'} board={userPrimaryGrid} enemyArray={computerTrackingGrid} /> </div> ); }; export default Main;
第三步:确认子组件没有修改props数组
虽然你说子组件只是依赖board.array渲染,但还是要检查子组件里有没有直接修改props.board.array的元素(比如props.board.array[x][y] = ...)。因为React的props是引用类型,直接修改会影响父组件中的原数组,导致数据不一致。
验证方式
修改完成后,你可以:
- 对比父组件和子组件的
console.log输出,看array是否一致; - 检查
randomPlaceShip的日志是否只输出一次,不会重复触发; - 如果是开发环境,可以暂时关闭React严格模式(去掉
index.js里的<StrictMode>标签),验证是否因为双重渲染导致的重复创建。
内容的提问来源于stack exchange,提问作者Carlos Gonzalez
相关产品推荐
相关产品推荐

