React native 在前台屏幕上更新全局状态时,即使屏幕处于后台,也会调用useFocusEffect挂钩

React native 在前台屏幕上更新全局状态时,即使屏幕处于后台,也会调用useFocusEffect挂钩,react-native,react-navigation,react-navigation-v5,React Native,React Navigation,React Navigation V5,我正在开发一个本地项目。这个问题主要是关于我的项目中的钩子行为 我有几个屏幕。有一个共享数据&每个屏幕都可以更新数据。因此,我决定使用context通过useStatehook托管数据。当一个屏幕设置MyData()时,所有屏幕都可以使用最新数据 我的数据上下文通过useStatehook托管共享数据: import React, {useState} from 'react'; const MyDataContext = React.createContext(); export cons

我正在开发一个本地项目。这个问题主要是关于我的项目中的钩子行为

我有几个屏幕。有一个共享数据&每个屏幕都可以更新数据。因此,我决定使用
context
通过
useState
hook托管数据。当一个屏幕
设置MyData(
)时,所有屏幕都可以使用最新数据

我的数据上下文通过
useState
hook托管共享数据:

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;
正如您所看到的,我有一个按钮,可以将用户导航到另一个屏幕。另一个屏幕具有与
useFocusEffect
钩子相同的结构,它在钩子中处理和更新全局状态的数据

当我运行我的应用程序时,以下情况发生在我身上:

  • 首先,
    MyScreenOne
    启动<调用code>useFocusEffect,通过
    setMyData()

  • 由于在上述步骤中调用了
    setMyData()
    ,因此会发生重新渲染,此时不会再次调用
    MyScreenOne
    useFocusEffect
    ,这是很好的,也是意料之中的

  • 现在我按下导航到
    MyScreenTwo
    的按钮。在
    MyScreenTwo
    上也会发生相同的过程:
    useFocusEffect
    被调用,数据被处理和更新,并通过
    setMyData()
    设置为全局状态。注意:
    MyScreenOne
    现在不可见,并且在后台堆栈/内存中

  • 因为在上述步骤中,全局状态由第二个屏幕更新,所以重新渲染会再次发生在内存中的所有屏幕上。这一次令人惊讶的是,
    MyScreenOne
    useFocusEffect
    再次被调用,因为
    MyScreenOne
    中的钩子再次更新了全局状态,内存中的屏幕再次被重新渲染

  • 正如您可以想象的那样,由于在上面的步骤中,后台屏幕
    MyScreenOne
    useFocusEffect
    被意外调用,现在会发生无休止的重新渲染


  • useFocusEffect
    不应该只在屏幕可见时运行吗?为什么在重新渲染时也会调用背景屏幕的
    useFocusEffect
    hook?如何实现我只需在每个屏幕上运行一次流程数据和更新数据,同时屏幕可见,所有屏幕都可以共享数据?

    UseFocuseEffect
    不采用依赖关系数组。您需要传递文档中提到的
    useCallback

    useFocusEffect(
    React.useCallback(()=>{
    //随便
    }, [])
    );
    

    好的!谢谢!
    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>
              )
    }
    ...