[英]Can't Access React Reducer Value from Function
In the code below, a keypress event detector is implemented through useEffect
which attempts to update index
through the useReducer
function.在下面的代码中,按键事件检测器是通过useEffect
实现的,它尝试通过useReducer
function 更新index
。 However, the console.log
output doesn't seem to show that the update works even though the button
component's value updates.但是,即使button
组件的值更新, console.log
output 似乎也没有显示更新有效。
On the other hand, when the button is clicked, the index
variable seems to update as indicated by the console.log
and the content of the button
also updates as expected.另一方面,当单击按钮时, index
变量似乎会按照console.log
的指示进行更新,并且button
的内容也会按预期更新。
Why is there such a disparity and - if I needed to access the updated index
variable after a keypress, how could I go about doing it?为什么会有这样的差异 - 如果我需要在按键后访问更新的index
变量,我怎么能 go 这样做呢?
The code is below:代码如下:
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
is redefined on every render, and has a closure around the value of counter
at the time it is defined. incrementCounter
在每次渲染时都会重新定义,并且在定义时在counter
的值周围有一个闭包。 In the keydown
handler's case, this is 0
(since your effect only runs once).在keydown
处理程序的情况下,这是0
(因为您的效果只运行一次)。 Notice that the the onClick
version is also always n-1
behind the button
text.请注意, onClick
版本也始终在button
文本后面n-1
。
You can move your logging into your reducer:您可以将日志记录移动到减速器中:
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>
Or use a functional setState
:或使用功能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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.