如何避免React功能组件过时的状态

时间:2019-10-23 14:06:59

标签: reactjs

我正在React中创建一个游戏,该游戏也使用Google Firestore来跟踪游戏数据。

在游戏中,用户将点击“开始”并连接到Google Firebase集合,该集合开始侦听数据库的更改。当数据库中的某些内容发生更改时,React组件的状态也会更改。

我遇到的问题是,我的侦听器的回调函数使用的state版本似乎已过时。响应播放器按下开始按钮而设置了侦听器,此时该组件的state似乎已被缓存。

有问题的组件如下:

import React, { useEffect, useState } from "react";

function Counter() {
  const [state, setFullState] = useState({
    count: 0,
    clicks: 0,
    started: false
  });

  const setState = update => {
    setFullState(prevState => {
      return {
        ...prevState,
        ...update
      };
    });
  };

  const handleStart = () => {
    const increment = () => {
      const { clicks } = state;
      setState({ clicks: clicks + 1 });
    };
    setState({
      started: true
    });
    document.addEventListener("click", increment);
  };

  const { clicks, count, started } = state;

  if (!started) {
    return (
      <div>
        <button onClick={handleStart}>START</button>
      </div>
    );
  }

  return (
    <div>
      <h2>Hooks</h2>
      <p>Count: {count}</p>
      <p>Clicks: {clicks}</p>
      <p>
        <button
          onClick={() => {
            setState({ count: count + 1 });
          }}
        >
          More
        </button>
      </p>
    </div>
  );
}

export default Counter;

我创建了一个sandbox来演示此问题。当您单击按钮时,“点击数”不会增加。

什么是使函数在调用时而不是在创建时引用组件的state的好方法?

1 个答案:

答案 0 :(得分:0)

使用useRef可以使状态快照在现在过时的increment回调中可见,并保持同步。

const currentState = React.useRef(state)
currentState.current = state

然后

  const handleStart = () => {
    const increment = () => {
      const { clicks } = currentState.current;
      setState({ clicks: clicks + 1 });
    };
    setState({
      started: true
    });
    document.addEventListener("click", increment);
  };

这应该可以回答您的问题,但是可以用比这更好的方法来解决您的问题。