无法从函数访问 React Reducer 值

Can't Access React Reducer Value from Function

在下面的代码中,按键事件检测器是通过 useEffect 实现的,它尝试通过 useReducer 函数更新 index。但是,即使 button 组件的值更新,console.log 输出似乎也没有显示更新有效。

另一方面,单击按钮时,index 变量似乎按照 console.log 的指示更新,button 的内容也按预期更新。

为什么会有这样的差异 - 如果我需要在按键后访问更新的 index 变量,我该怎么做呢?

代码如下:

const { useEffect, useReducer } = React;

const indexReducer = (state, action) => {
  if (action === "decrease") {
    return state-1
  } else if (action === "increase") {
    return state+1
  } else if (action === "reset") {
    return 0
  }
}

function App() {
  const [counter, setCounter] = useReducer(indexReducer, 0)
  const incrementCounter = () => {
    console.log(counter)
    setCounter("increase")
  }

  useEffect(() => {
    document.addEventListener("keydown", incrementCounter, false);

    return () => {
      document.removeEventListener("keydown", incrementCounter, false);
    };
  }, []);
  return (
    <div className="App">
      <button onClick={incrementCounter}>{"COUNT: " + counter}</button>
    </div>
  );
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

incrementCounter 在每个渲染器上都被重新定义,并且在定义时围绕 counter 的值有一个闭包。在 keydown 处理程序的情况下,这是 0 (因为您的效果只运行一次)。请注意,onClick 版本也始终 n-1button 文本之后。

您可以将日志移至您的减速器中:

const { useEffect, useReducer } = React;

const indexReducer = (state, action) => {
  if (action === "decrease") {
    return state-1
  } else if (action === "increase") {
    console.log(state+1)
    return state+1
  } else if (action === "reset") {
    return 0
  }
}

function App() {
  const [counter, setCounter] = useReducer(indexReducer, 0)
  const incrementCounter = () => {
    setCounter("increase")
  }

  useEffect(() => {
    document.addEventListener("keydown", incrementCounter, false);

    return () => {
      document.removeEventListener("keydown", incrementCounter, false);
    };
  }, []);
  return (
    <div className="App">
      <button onClick={incrementCounter}>{"COUNT: " + counter}</button>
    </div>
  );
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

或者使用函数 setState:

const { useEffect, useState } = React;

function App() {
  const [counter, setCounter] = useState(0)
  const incrementCounter = () => {
    setCounter(counter => {
      console.log(counter + 1)
      return counter + 1         
    })
  }

  useEffect(() => {
    document.addEventListener("keydown", incrementCounter, false);

    return () => {
      document.removeEventListener("keydown", incrementCounter, false);
    };
  }, []);
  return (
    <div className="App">
      <button onClick={incrementCounter}>{"COUNT: " + counter}</button>
    </div>
  );
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>