Hooks useCallback在刷新列表时保持使用旧值



下面的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,因为要使用useStateuseCallback,您必须了解这两件不同的事情。

范围:

假设您有一个名为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/

感谢

相关内容

  • 没有找到相关文章

最新更新