【问题标题】:Can't Access React Reducer Value from Function无法从函数访问 React Reducer 值
【发布时间】:2021-08-23 16:46:59
【问题描述】:

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

另一方面,当单击按钮时,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>

【问题讨论】:

    标签: javascript reactjs use-effect use-reducer


    【解决方案1】:

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

    您可以将您的日志记录移动到您的减速器中:

    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>

    【讨论】:

    • 我明白你的意思。您能否建议一种我仍然可以使用按键但更新counter的方法
    • 你可以登录你的reducer而不是你的handler,或者使用useState的功能版本来存储计数器并在那里记录。
    • 对不起,我真的很陌生。你能举个例子吗?我不太清楚你的意思
    • 无需道歉。我已经编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2018-11-27
    • 2017-04-02
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 2020-11-20
    • 2014-01-31
    相关资源
    最近更新 更多