我有以下代码:
import React, { useState, useEffect} from 'react';
import Board from './Board';
import Player from '../functions/Player'
function Game() {
const [computer, setComputer] = useState(Player(1,false));
const [computerBoard, setComputerBoard] = useState(new Array(100).fill(-1));
const sendAttack = (location) => {
// Activates everytime I click Board component
let compCopy = computer;
compCopy.receiveAttack(location);
setComputer(compCopy);
setComputerBoard(compCopy.getHitBoard());
console.log(compCopy.getHitBoard()); // always prints, each time I do sendAttack()
// and the hitBoard does change, shows a different hitBoard everytime I click!
}
useEffect(() => {
console.log('something has changed') // print (twice for some reason) only on render, why?
})
useEffect(() => {
console.log('computer hit has changed') // prints only on render and on the first setAttack()
},[computer]);
useEffect(() => {
console.log('computer board has changed') // prints on render
// and once it works but only on first sendAttack()
},[computerBoard])
return (
<div className="game">
<Board hitBoard ={computer.getHitBoard()} sendAttack={sendAttack} />
</div>
);
}
export default Game;
问题是我希望 Board
组件 hitBoard prop
会在 sendAttack()
完成更新时不断更新。但是除了渲染之外它永远不会更新它(实际上只有第一次 sendAttack() 一次)。我不明白为什么当我 setComputer
它不启动 useEffect()
我的代码中是否有明显的错误?感谢您的提示。
答案 0 :(得分:2)
我不认为您的 compCopy 实际上是一个新对象。如果对象没有不同,那么 setComputer 可能不会不同,因此不会触发效果。尝试类似 let compCopy = makeANewCopyOf(computer)
的内容,这样 compCopy 是您自己克隆的全新对象。
答案 1 :(得分:2)
上面@Atmas 给出的答案是正确的。我会通过让 receiveAttack()
返回一个新对象来稍微调整它,该对象是带有其他更改的传入对象的副本。一般来说,这是一个更强大的数据管理解决方案 - 不要修改对象,创建新对象并返回它们。此外,在 React 和各种 React 库中,你会经常遇到比较对象 ID 而不是对象内容的想法。
这是一个有用的指南,它准确地讨论了您要做什么 - 使用对象作为 React 状态变量:
此外,您不需要 useEffect()
来调试这些东西。当组件重新渲染时,将在 return 语句正上方放置一个常规的 ol' 控制台日志。