javascript - React hooks:从回调中访问最新状态
问题描述
编辑(2020 年 6 月 22 日):由于这个问题有一些新的兴趣,我意识到可能存在一些混淆点。所以我想强调一下:问题中的示例旨在作为玩具示例。它不能反映问题。引发这个问题的问题是使用第三方库(对其控制有限),该库将回调作为函数的参数。为该回调提供最新状态的正确方法是什么。在反应类中,这将通过使用this
. 在 React hooks 中,由于 state 被封装在 的函数中的方式React.useState()
,如果回调通过获得状态React.useState()
,它将是陈旧的(设置回调时的值)。但如果它设置状态,它将通过传递的参数访问最新状态。这意味着我们可以通过将状态设置为与原来相同的方式,在使用 React 钩子的回调中获取最新状态。这有效,但违反直觉。
-- 原始问题在下面继续 --
我正在使用 React 钩子并尝试从回调中读取状态。每次回调访问它时,它都会返回其默认值。
使用以下代码。Count is: 0
无论我点击多少次,控制台都会继续打印。
function Card(title) {
const [count, setCount] = React.useState(0)
const [callbackSetup, setCallbackSetup] = React.useState(false)
function setupConsoleCallback(callback) {
console.log("Setting up callback")
setInterval(callback, 3000)
}
function clickHandler() {
setCount(count+1);
if (!callbackSetup) {
setupConsoleCallback(() => {console.log(`Count is: ${count}`)})
setCallbackSetup(true)
}
}
return (<div>
Active count {count} <br/>
<button onClick={clickHandler}>Increment</button>
</div>);
}
const el = document.querySelector("#root");
ReactDOM.render(<Card title='Example Component' />, el);
您可以在此处找到此代码
我在回调中设置状态没有问题,只有在访问最新状态时。
如果我猜测一下,我认为任何状态变化都会创建 Card 函数的新实例。并且回调指的是旧的。根据https://reactjs.org/docs/hooks-reference.html#functional-updates上的文档,我想到了在回调中调用 setState 的方法,并将函数传递给 setState,看看是否我可以从 setState 中访问当前状态。更换
setupConsoleCallback(() => {console.log(`Count is: ${count}`)})
和
setupConsoleCallback(() => {setCount(prevCount => {console.log(`Count is: ${prevCount}`); return prevCount})})
您可以在此处找到此代码
这种方法也没有奏效。编辑:实际上第二种方法确实有效。我只是在我的回调中有一个错字。这是正确的做法。我需要调用 setState 来访问之前的状态。即使我无意设置状态。
我觉得我对 React 类采取了类似的方法,但是。为了代码的一致性,我需要坚持使用 React Effects。
如何从回调中访问最新的状态信息?
解决方案
对于您的场景(您不能继续创建新的回调并将它们传递给您的 3rd 方库),您可以使用useRef
以保持具有当前状态的可变对象。像这样:
function Card(title) {
const [count, setCount] = React.useState(0)
const [callbackSetup, setCallbackSetup] = React.useState(false)
const stateRef = useRef();
// make stateRef always have the current count
// your "fixed" callbacks can refer to this object whenever
// they need the current value. Note: the callbacks will not
// be reactive - they will not re-run the instant state changes,
// but they *will* see the current value whenever they do run
stateRef.current = count;
function setupConsoleCallback(callback) {
console.log("Setting up callback")
setInterval(callback, 3000)
}
function clickHandler() {
setCount(count+1);
if (!callbackSetup) {
setupConsoleCallback(() => {console.log(`Count is: ${stateRef.current}`)})
setCallbackSetup(true)
}
}
return (<div>
Active count {count} <br/>
<button onClick={clickHandler}>Increment</button>
</div>);
}
您的回调可以引用可变对象来“读取”当前状态。它将在其闭包中捕获可变对象,并且每次渲染可变对象都将使用当前状态值进行更新。
推荐阅读
- php - MySql 5.7:一般错误:1366 Incorrect integer value: '' for TinyInt(1) field
- android - 如何在接收焦点时消失 TextInputEditText 中的提示
- .net - 在 dotnet 命令行中出现 SSL 错误
- r - 当先知模型循环运行时,R 崩溃
- xamarin.forms - 图像不会在 xamarin 中显示
- mysql - 如何在 mysql 查询中总计“AS”列?
- r - Continuous x 审美——你忘了 aes(group=...) 是什么意思吗?
- php - 在另一个文件中执行后如何使用php变量的值
- sql-server-2008 - SQL 查询 - 使用 openquery 无法正常工作
- python - 一次一批