简体   繁体   English

React 的问题不更新 state(挂钩)

[英]Trouble with React not updating state (hooks)

I have a small memory game that I am building to learn React.我有一个 memory 小游戏,我正在构建它来学习 React。 The idea is that you click a tile, it is shuffled, and you try to pick one you haven't already selected.这个想法是,您单击一个图块,它会被打乱,然后您尝试选择一个您尚未选择的图块。 The problem is I can't seem to get my internal state for which tiles have previously been seen to update.问题是我似乎无法获取我的内部 state,之前已经看到它更新了磁贴。

Here is my component:这是我的组件:

const Gameboard = (props) => {
  const [tiles, setTiles] = useState([]);
  const [currentScore, setCurrentScore] = useState(0);
  const [highScore, setHighScore] = useState(0);
  const [previouslySeen, setPreviouslySeen] = useState([]);

  const handleClick = (evt) => {
    const tile = evt.target;
    if (!previouslySeen.includes(tile)) {
      setCurrentScore(current => current + 1);
      props.setCurrentScore(current => current + 1);
      setPreviouslySeen([...previouslySeen, tile]);
    } else {
      alert("Game over, thanks for playing!");
      if (currentScore > highScore) {
        setHighScore(currentScore);
        props.setHighScore(currentScore);
      }
      setCurrentScore(0);
      props.setCurrentScore(0);
      setPreviouslySeen([]);
    }
  };

  const generateTiles = (tileCount) => {
    return [...Array(tileCount).keys()].map((n) => {
      return <Tile key={n} number={n} handleClick={handleClick} />;
    });
  };

  const shuffleTiles = (tiles) => {
    let tilesCopy = [...tiles];

    for (let i = tilesCopy.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * i);
      const temp = tilesCopy[i];
      tilesCopy[i] = tilesCopy[j];
      tilesCopy[j] = temp;
    }

    return tilesCopy;
  };

  useEffect(() => {
    const initialTiles = generateTiles(props.tileCount);
    setTiles(shuffleTiles(initialTiles));
  }, []);

  useEffect(() => {
    setTiles((oldTiles) => {
      const newTiles = shuffleTiles(oldTiles);
      return newTiles;
    });
  }, [currentScore, highScore]);

  return <div className="Gameboard">{tiles}</div>;
};

The handleClick method gets passed into the individual Tile components and is just called with onClick . handleClick方法被传递到各个Tile组件中,并且仅使用onClick进行调用。 The handleClick method is what is giving me trouble, it seems as if it doesn't ever update previouslySeen`, and I have similar problems with setting the high score in the parent component so that it is reflected in the UI. handleClick method is what is giving me trouble, it seems as if it doesn't ever update过 previouslySeen`,我在父组件中设置高分以使其反映在 UI 中时遇到类似的问题。 How are you supposed to handle updates like this in React?你应该如何在 React 中处理这样的更新?

Try this:试试这个:

const handleClick = (evt) => {
const tile = evt.target;
if (!previouslySeen.includes(tile)) {
  setCurrentScore(current => current + 1);
  props.setCurrentScore(current => current + 1);
  // Change the following line:
  setPreviouslySeen(previousState => [...previousState, tile]);
} else {

Also, you're getting setCurrentScore, setHighScore from parent props and from declaring states:此外,您将从父属性声明状态中获取setCurrentScore, setHighScore

  const [currentScore, setCurrentScore] = useState(0);
  const [highScore, setHighScore] = useState(0);

So essentially you're keeping two separate currentScore and highScore states - one in the Gameboard component, and one in its parent.所以基本上你保持两个独立的currentScorehighScore状态 - 一个在Gameboard组件中,一个在它的父组件中。 It's best to delete these state variables and setters from Gameboard and get them directly from parent props.最好从Gameboard中删除这state个变量和setter,直接从parent props中获取。

It turned out that it was because I was storing JSX elements directly in state. Removing that and instead just storing the tile value (plain JS strings) fixed the issue where state wasn't being correctly updated.事实证明,这是因为我将 JSX 元素直接存储在 state 中。删除它并仅存储平铺值(纯 JS 字符串)解决了 state 未正确更新的问题。 Quite the gotcha!真是陷阱!

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

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