首先,我无法找出这段代码中的问题。但也许这个问题在这里有一席之地。
据我所知,问题可能是单击按钮后计数器值没有更新。当按钮被点击时,警报显示了值,尽管在2.5秒的延迟期间,我点击并增加了计数器的值。
我是对的,如果是的话,应该在这里修复或添加什么?
import React, { useState } from 'react'
function Root() {
const [count, setCount] = useState(0)
function handleAlertClick() {
setTimeout(() => {
alert(`You clicked ${count} times`)
}, 2500)
}
return (
<Container>
<Column>
<h4>Closures</h4>
<p>You clicked {count} times</p>
<button type="button" onClick={() => setCount(counter => counter + 1)}>
Click me
</button>
<button type="button" onClick={handleAlertClick}>
Show alert
</button>
</Column>
</Container>
)
}
export default Root
问题
当setTimeout
被调用时,它的回调函数在Root
组件当前渲染中count
的电流值上关闭。
在计时器到期之前,如果您更新count
,这会导致组件的重新渲染,但是setTimeout
的回调函数仍然看到在效果中当setTimeout
被调用时的值。这是代码中闭包导致的问题的要点。
Root
组件的每个渲染都有自己的状态,道具,组件内部定义的局部函数;简而言之,组件的每次渲染都与之前的渲染是分开的。
State在组件的特定渲染中是常量;组件在重新呈现之前无法看到更新后的状态。在之前的渲染中设置的任何计时器都将看到它关闭的值;它无法看到更新后的状态
<<p>解决方案/strong>您可以使用useRef
钩子来解决由于闭包而引起的问题。
你可以在每次重新渲染Root
组件时更新ref。这允许我们在ref.
count
的最新值。一旦你有一个ref,而不是传递count
给alert
,传递ref。这确保alert总是显示count
的最新值。
function Root() {
const [count, setCount] = React.useState(0)
const countRef = React.useRef(count);
// assign the latest value of "count" to "countRef"
countRef.current = count;
function handleAlertClick() {
setTimeout(() => {
alert(`You clicked ${countRef.current} times`)
}, 2500)
}
return (
<div>
<h4>Closures</h4>
<p>You clicked {count} times</p>
<button type="button" onClick={() => setCount(counter => counter + 1)}>
Click me
</button>
<button type="button" onClick={handleAlertClick}>
Show alert
</button>
</div>
)
}
ReactDOM.render(<Root/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>