You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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是引用类型,直接修改会影响父组件中的原数组,导致数据不一致。

验证方式

修改完成后,你可以:

  1. 对比父组件和子组件的console.log输出,看array是否一致;
  2. 检查randomPlaceShip的日志是否只输出一次,不会重复触发;
  3. 如果是开发环境,可以暂时关闭React严格模式(去掉index.js里的<StrictMode>标签),验证是否因为双重渲染导致的重复创建。

内容的提问来源于stack exchange,提问作者Carlos Gonzalez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:12:32