简体   繁体   English

当 State 更改时,useEffect() Hook 不会更新

[英]useEffect() Hook doesn't update when State Change

I have the following code:我有以下代码:

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;

The problem is that I want that the Board components hitBoard prop will keep getting updated whenever sendAttack() has finished updating.问题是我希望Board组件 hitBoard propsendAttack()完成更新时不断更新。 But it never does update it except on render (and actually just one time for the first sendAttack()).但它永远不会更新它,除非在渲染时(实际上只在第一次 sendAttack() 时更新一次)。 I don't understand why when I setComputer it doesn't initiate a useEffect()我不明白为什么当我setComputer它没有启动useEffect()

Is there an obvious mistake in my code?我的代码中有明显的错误吗? Thanks for the tips.感谢您的提示。

I don't think your compCopy is actually a new object.我不认为你的 compCopy 实际上是一个新的 object。 If the object isn't different then setComputer likely won't be different therefore the effect won't trigger.如果 object 没有不同,那么 setComputer 可能不会不同,因此不会触发效果。 Try something like let compCopy = makeANewCopyOf(computer) such that compCopy is a brand new object that you have cloned yourself.尝试类似let compCopy = makeANewCopyOf(computer)这样 compCopy 是您自己克隆的全新 object。

The answer given by @Atmas above, is correct.上面@Atmas 给出的答案是正确的。 I'd tweak it a bit by having receiveAttack() return a new object that is a copy of the one passed in with the additional changes.我会通过让receiveAttack()返回一个新的 object 来稍微调整一下,它是传递的附加更改的副本。 That's a more robust solution to data management in general - don't modify objects, make new ones and return them.一般来说,这是一种更强大的数据管理解决方案——不要修改对象,创建新对象并返回它们。 Also, that idea of comparing object IDs rather than the content of the object is something you're going to hit all the time in React and various React libraries.此外,比较 object ID 而不是 object 的内容的想法是您将在 React 和各种 React 库中一直遇到的问题。

Here's a useful guide that talks about exactly what you're trying to do - use an object as a React state variable:这是一个有用的指南,它确切地讨论了你正在尝试做的事情 - 使用 object 作为 React state 变量:

https://blog.logrocket.com/a-guide-to-usestate-in-react-ecb9952e406c/#usinganobjectasastatevariablewithusestatehook https://blog.logrocket.com/a-guide-to-usestate-in-react-ecb9952e406c/#usinganobjectasastatevariablewithusestatehook

Also, you don't need a useEffect() to debug this stuff.此外,您不需要useEffect()来调试这些东西。 Just a regular ol' console log placed right above your return statement will print when the component re-renders.当组件重新渲染时,将在您的 return 语句正上方放置一个常规的 ol' 控制台日志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM