下面的useCallback有什么问题,每次调用函数onRefresh
时我都不会得到下面的值?如何使其返回预期值using Hooks
?
调用Refresh 2x时的示例
预期值:
true
0
20
false
true
0
20
false
值:接收的
false
0
0
false
false
20
20
false
状态变量的初始化
const [refreshing, setRefreshing] = useState(false)
const [offsetQuestions, setOffsetQuestions] = useState(0)
使用useCallback:的函数调用
const fetchSomeData = async () => {
await new Promise(resolve => setTimeout(resolve, 3000)) // 3 sec
}
const onRefresh = useCallback( async () => {
setRefreshing(true)
setOffsetQuestions(0)
console.log(refreshing)
console.log(offsetQuestions)
await fetchSomeData()
setOffsetQuestions(20)
setRefreshing(false)
console.log(offsetQuestions)
console.log(refreshing)
}, [refreshing, offsetQuestions])
调用函数的位置:
<FlatList
data={questionsLocal}
refreshing={refreshing}
onRefresh={onRefresh}
...
/>
您得到的是钩子中的预期行为这一切都是关于闭包的。react中的每个渲染都有自己的道具、状态、函数和事件处理程序,对于特定的渲染,它们永远保持不变。所以这里发生的是,useCallback
在特定渲染的状态变量上是关闭的,所以即使在setState
之后,console.log
也会因为闭合而始终为您提供该特定渲染的态值。
这种情况让许多开始使用钩子的开发人员感到困惑。您可能会认为React将是被动的,并且在您调用setX
后会更改状态的值,但如果您仔细想想,您就不能指望React停止执行流更改状态变量并继续执行。
因此,您得到的是useCallback
创建范围中的状态变量(反复读取(。
让我们将其分解为两个部分,作用域和useCallback,因为要使用useState
和useCallback
,您必须了解这两件不同的事情。
范围:
假设您有一个名为age
的状态和一个写入/读取该状态的函数(目前,不使用useCallback
(
const [age, setAge] = useState(42);
const increaseAge = () => {
setAge(age + 1); // this "age" is the same "age" from above
console.log(age); // also this one
}
从中可以看出,每次渲染都会定义一个新的age
变量(如果值由React给定(,还定义了一个新increaseAge
函数,可以访问包含age
变量的范围。
这就是作用域的工作方式,这就是为什么在调用setAge
之后没有获得age
的新值。为了能够在age
上获得一个新值,React必须重新渲染组件,因此将在新的作用域上定义一个新的age
变量。这正是调用setAge
后发生的情况,React将触发一个新的渲染。
使用回调
现在,假设您不想一次又一次地定义increaseAge
函数,您希望保持相同的引用(可以帮助防止无用的渲染(。这就是您想要使用useCallback
的地方。
当使用useCallback
时,React为每个渲染提供相同的函数引用,除非其中一个依赖项发生更改。
如果不给useCallback
提供依赖项,React将不会重新创建函数,函数将访问其创建的作用域(第一次渲染(,当给useCallback
提供正确的依赖项时,它将被重新创建,现在可以访问具有最新状态变量的作用域。
这应该解释为什么必须提供依赖项,以及如何访问状态变量(范围(。
您可以使用UseRef钩子来使用state的当前值,而不是词法值。
const ref = useRef();
useEffect(() => {
ref.current = value;
});
这就是如何在引用中设置值并在任何需要的地方使用它。
以下是您可以详细了解此问题并提出可能解决方案的链接https://dmitripavlutin.com/react-hooks-stale-closures/
感谢