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

React开发问题:子组件未接收父组件更新后的状态数组

React状态更新后子组件未接收新值问题

我在用React开发一款类似Yahtzee的游戏,遇到父组件更新后的值无法传递给子组件的问题:

  • 点击当前回合的骰子时,调用方法将current数组对应位置设为0,并把该骰子的值同步到keep数组对应位置;
  • 点击keep数组中的骰子时,值反向传递到current数组,最终每个骰子应显示对应数组项的当前值。

点击任意数组中的骰子后,通过console.log验证,current和keep数组的状态已正确更新,但更新后的数组似乎未传递给子组件(同样通过console.log验证)。


相关代码

Game.js

const Game = () => {
  const [currentValues, setCurrentValues] = useState([0, 0, 0, 0, 0, 0]);
  const [keepValues, setKeepValues] = useState([0, 0, 0, 0, 0, 0]);
  
  const moveCurrentToKeep = (index) => {
    if (currentValues[index] > 0) {
      let curr = currentValues;
      let keep = keepValues;
      let valueToSwitch = curr[index];
      curr[index] = 0;
      keep[index] = valueToSwitch;
      setCurrentValues(curr);
      setKeepValues(keep);
      console.log("Curr: " + currentValues); // 输出看似正确
      console.log("Keep: " + keepValues); // 输出看似正确
    }
  };
  
  const moveKeepToCurrent = (index) => {
    if (keepValues[index] > 0) {
      let curr = currentValues;
      let keep = keepValues;
      let valueToSwitch = keep[index];
      keep[index] = 0;
      curr[index] = valueToSwitch;
      setCurrentValues(curr);
      setKeepValues(keep);
      console.log("Curr: " + currentValues); // 输出看似正确
      console.log("Keep: " + keepValues); // 输出看似正确
    }
  };
  
  return (
    <div>
      <Current values={currentValues} onDiceClicked={moveCurrentToKeep} />
      <Keep values={keepValues} onDiceClicked={moveKeepToCurrent} />
    </div>
  );  
}

Current.js

const Current = ({ values, onDiceClicked }) => {
  console.log("Current: " + values); // 无输出!!!
  return (
    <div>
      <DiceField value={values[0]} onClick={() => onDiceClicked(0)} />
      <DiceField value={values[1]} onClick={() => onDiceClicked(1)} />
      <DiceField value={values[2]} onClick={() => onDiceClicked(2)} />
      <DiceField value={values[3]} onClick={() => onDiceClicked(3)} />
      <DiceField value={values[4]} onClick={() => onDiceClicked(4)} />
      <DiceField value={values[5]} onClick={() => onDiceClicked(5)} />
    </div>
  );
};

Keep.js

const Keep = ({ values, onDiceClicked }) => {
  console.log("Keep: " + values); // 无输出!!!
  return (
    <div>
      <DiceField value={values[0]} onClick={() => onDiceClicked(0)} />
      <DiceField value={values[1]} onClick={() => onDiceClicked(1)} />
      <DiceField value={values[2]} onClick={() => onDiceClicked(2)} />
      <DiceField value={values[3]} onClick={() => onDiceClicked(3)} />
      <DiceField value={values[4]} onClick={() => onDiceClicked(4)} />
      <DiceField value={values[5]} onClick={() => onDiceClicked(5)} />
    </div>
  );
};

DiceField.js

const DiceField = ({ value, onClick }) => {
  return (
    <button onClick={onClick}>
      {value !== 0 ? value : ""}
    </button>
  );
};

问题原因与修复方案

核心问题

你直接修改了React状态数组的引用:

let curr = currentValues; // 只是复制了数组的引用,不是新数组
let keep = keepValues;

React通过浅比较判断状态是否变化,当你修改原数组并把同一个引用传给setCurrentValues/setKeepValues时,React会认为状态没有改变,不会触发组件重新渲染,子组件自然接收不到新值。

另外,你看到的console.log输出看似正确,是因为你直接篡改了原数组的内容,虽然状态没更新,但原数组已经被修改,这违背了React状态不可变的原则。

修复代码

修改moveCurrentToKeep和moveKeepToCurrent方法,创建数组的新副本再修改:

const Game = () => {
  const [currentValues, setCurrentValues] = useState([0, 0, 0, 0, 0, 0]);
  const [keepValues, setKeepValues] = useState([0, 0, 0, 0, 0, 0]);
  
  const moveCurrentToKeep = (index) => {
    if (currentValues[index] > 0) {
      // 创建数组副本,避免修改原状态引用
      const curr = [...currentValues];
      const keep = [...keepValues];
      const valueToSwitch = curr[index];
      curr[index] = 0;
      keep[index] = valueToSwitch;
      setCurrentValues(curr);
      setKeepValues(keep);
    }
  };
  
  const moveKeepToCurrent = (index) => {
    if (keepValues[index] > 0) {
      const curr = [...currentValues];
      const keep = [...keepValues];
      const valueToSwitch = keep[index];
      keep[index] = 0;
      curr[index] = valueToSwitch;
      setCurrentValues(curr);
      setKeepValues(keep);
    }
  };
  
  return (
    <div>
      <Current values={currentValues} onDiceClicked={moveCurrentToKeep} />
      <Keep values={keepValues} onDiceClicked={moveKeepToCurrent} />
    </div>
  );  
}

额外说明

  • 用扩展运算符[...arr]是创建一维数组浅副本的简单方式,也可以用arr.slice()或Array.from(arr);
  • 如果是嵌套对象/数组,需要使用深拷贝,但这里是一维数组,浅拷贝足够;
  • 始终遵守React状态不可变原则,避免直接修改状态值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:01:11