当在前台屏幕上更新全局状态时,即使屏幕在后台也会调用 useFocusEffect 挂钩
useFocusEffect hook is invoked even screen is in background when update global state on the screen in foreground
我正在开发 react-native 项目。这个问题主要是关于我项目中的useFocusEffect钩子行为
我有几个屏幕。有一个共享数据&每个屏幕都可以更新数据。因此,我决定使用 context
通过 useState
挂钩来托管数据。当一屏setMyData(
)时,所有屏都可以看到最新的数据
我的数据上下文通过 useState
挂钩托管共享数据:
import React, {useState} from 'react';
const MyDataContext = React.createContext();
export const MyDataProvider = ({children}) => {
const [myData, setMyData] = useState([]);
...
return (
<MyDataContext.Provider
value={{
myData,
setMyData,
}}>
{children}
</MyDataContext.Provider>
);
}
export default MyDataContext;
(我的 App
组件被 MyDataContext.Provider
包裹着,我只是不在这里显示那部分,因为这不是我的问题的重点)
在我的每个屏幕组件中,当屏幕在前台(可见)时,我需要处理我的数据一次,并用更新后的数据更新全局状态。我使用 useFocusEffect 挂钩。如下所示:
import {useFocusEffect} from '@react-navigation/native';
import MyDataContext from '../context/MyDataContext';
const MyScreenOne = ({navigation})=> {
const {myData, setMyData} = useContext(MyDataContext);
useFocusEffect(() => {
console.log('################# Screen one is FOCUSED! ');
const updatedData = processData([...myData]);
// set my data
setMyData(updatedData);
return () => {
console.log('Screen one was unfocused');
};
}, []);//empty array to force code in hook only run once
return (<View>
<MyButton onPress={()=> navigation.navigate("MyScreenTwo")}>
...
</View>
)
}
...
如您所见,我有一个按钮可以将用户导航到另一个屏幕。另一个屏幕具有与 useFocusEffect
挂钩相同的结构,它在其中处理和更新全局状态数据。
当我 运行 我的应用程序时,以下情况发生在我身上:
首先MyScreenOne
启动。 useFocusEffect
被调用,数据被处理和更新并通过 setMyData()
设置为全局状态
由于上一步调用了setMyData()
,重新渲染,此时不会再调用MyScreenOne
的useFocusEffect
,很好,符合预期。
现在我按下导航到 MyScreenTwo
的按钮。 MyScreenTwo
上发生相同的过程:调用 useFocusEffect
,处理和更新数据并通过 setMyData()
设置为全局状态。注意:MyScreenOne
现在不可见并且在背景中 stack/memory。
由于在上面的步骤中全局状态由第二个屏幕更新,重新渲染再次发生在内存中的所有屏幕上。这次令人惊讶的是 MyScreenOne
的 useFocusEffect
再次被调用,因为全局状态再次被 MyScreenOne
中的钩子更新,并且重新渲染再次发生在内存中的屏幕上。
正如您可以想象的那样,由于在上述步骤中意外调用了背景屏幕 MyScreenOne
的 useFocusEffect
,现在会发生无休止的重新渲染。
难道 useFocusEffect
不应该是 运行 只有在屏幕可见时才应该是吗?为什么在重新渲染时也会调用背景屏幕的 useFocusEffect
钩子?如何实现我只需要 运行 在屏幕可见时在每个屏幕上处理数据和更新数据一次,同时数据可以被所有屏幕共享?
useFocusEffect
不采用依赖项数组。您需要按照文档中的说明传递 useCallback
:
useFocusEffect(
React.useCallback(() => {
// whatever
}, [])
);
我正在开发 react-native 项目。这个问题主要是关于我项目中的useFocusEffect钩子行为
我有几个屏幕。有一个共享数据&每个屏幕都可以更新数据。因此,我决定使用 context
通过 useState
挂钩来托管数据。当一屏setMyData(
)时,所有屏都可以看到最新的数据
我的数据上下文通过 useState
挂钩托管共享数据:
import React, {useState} from 'react';
const MyDataContext = React.createContext();
export const MyDataProvider = ({children}) => {
const [myData, setMyData] = useState([]);
...
return (
<MyDataContext.Provider
value={{
myData,
setMyData,
}}>
{children}
</MyDataContext.Provider>
);
}
export default MyDataContext;
(我的 App
组件被 MyDataContext.Provider
包裹着,我只是不在这里显示那部分,因为这不是我的问题的重点)
在我的每个屏幕组件中,当屏幕在前台(可见)时,我需要处理我的数据一次,并用更新后的数据更新全局状态。我使用 useFocusEffect 挂钩。如下所示:
import {useFocusEffect} from '@react-navigation/native';
import MyDataContext from '../context/MyDataContext';
const MyScreenOne = ({navigation})=> {
const {myData, setMyData} = useContext(MyDataContext);
useFocusEffect(() => {
console.log('################# Screen one is FOCUSED! ');
const updatedData = processData([...myData]);
// set my data
setMyData(updatedData);
return () => {
console.log('Screen one was unfocused');
};
}, []);//empty array to force code in hook only run once
return (<View>
<MyButton onPress={()=> navigation.navigate("MyScreenTwo")}>
...
</View>
)
}
...
如您所见,我有一个按钮可以将用户导航到另一个屏幕。另一个屏幕具有与 useFocusEffect
挂钩相同的结构,它在其中处理和更新全局状态数据。
当我 运行 我的应用程序时,以下情况发生在我身上:
首先
设置为全局状态MyScreenOne
启动。useFocusEffect
被调用,数据被处理和更新并通过setMyData()
由于上一步调用了
setMyData()
,重新渲染,此时不会再调用MyScreenOne
的useFocusEffect
,很好,符合预期。现在我按下导航到
MyScreenTwo
的按钮。MyScreenTwo
上发生相同的过程:调用useFocusEffect
,处理和更新数据并通过setMyData()
设置为全局状态。注意:MyScreenOne
现在不可见并且在背景中 stack/memory。由于在上面的步骤中全局状态由第二个屏幕更新,重新渲染再次发生在内存中的所有屏幕上。这次令人惊讶的是
MyScreenOne
的useFocusEffect
再次被调用,因为全局状态再次被MyScreenOne
中的钩子更新,并且重新渲染再次发生在内存中的屏幕上。正如您可以想象的那样,由于在上述步骤中意外调用了背景屏幕
MyScreenOne
的useFocusEffect
,现在会发生无休止的重新渲染。
难道 useFocusEffect
不应该是 运行 只有在屏幕可见时才应该是吗?为什么在重新渲染时也会调用背景屏幕的 useFocusEffect
钩子?如何实现我只需要 运行 在屏幕可见时在每个屏幕上处理数据和更新数据一次,同时数据可以被所有屏幕共享?
useFocusEffect
不采用依赖项数组。您需要按照文档中的说明传递 useCallback
:
useFocusEffect(
React.useCallback(() => {
// whatever
}, [])
);