导航容器刷新问题

问题描述 投票:0回答:1
function AppHome({colorMode, currentLang, restartApp}) {
    const default_scheme = useColorScheme()
    let [color_choice, setColor_choice] = useState(colorMode)
    let [lang, setLang] = useState(currentLang)

    const colors = {
        auto: color_choice === "auto",
        ...(color_choice === "light" || color_choice === "auto" && default_scheme === "light") ? LightColors : DarkColors
    }

    const Home = ({navigation, route}) => (
        <HomePage
        navigation={navigation}
        openPremium={() => {}}
        NavigationBar={() => {}}
        restartApp={restartApp}
        />
    )

    return (
        <LanguageContext.Provider value={{lang, setLang}} >
            <ThemeContext.Provider value={colors} >
                <NavigationContainer>     
                    <Tab.Navigator screenOptions={{
                        headerShown: false,
                        tabBarStyle: {display: 'none'},
                    }} >
                        <Tab.Screen name={'Home'} component={Home} />
                    </Tab.Navigator>
                </NavigationContainer>
            </ThemeContext.Provider>
        </LanguageContext.Provider>
    );
}

在此代码中,当我通过编辑设备主题或任何其他状态来更新

default_scheme
时,会触发 NavigationContainer 的重新渲染,这很好。但是,当发生这种情况时,选项卡屏幕会完全刷新,并且我所在的页面会丢失所有进度(例如我在文本输入上写的内容)。我怎样才能防止这种影响?

如果我检查 Home 组件并添加此代码

useEffect(() => {
     console.log("This log should appear ONCE.")
}, [])

当我之前谈到的每次刷新被触发时,都会出现日志。

javascript reactjs react-navigation
1个回答
0
投票

您有一个

Home
的组件定义在另一个组件定义(
AppHome
的定义)中实例化。这意味着该组件不是引用稳定的,任何
AppHome
的重新渲染都将完全重新创建
Home
组件,该组件将被完全卸载并重新安装,从而丢失该过程中的所有状态。

但是,我看到您希望这样做是因为

Home
需要访问
restartApp
,这是在
Home
的上下文中。

选项A

使

Home
成为第一类(参考稳定)组件,并使用
restartApp
children
 而不是 
Tab.Screen
属性将
component
传递给属性。

function Home({navigation, restartApp}) {
 return (
        <HomePage
        navigation={navigation}
        openPremium={() => {}}
        NavigationBar={() => {}}
        restartApp={restartApp}
        />
    )
}

function AppHome({colorMode, currentLang, restartApp}) {
    const default_scheme = useColorScheme()
    let [color_choice, setColor_choice] = useState(colorMode)
    let [lang, setLang] = useState(currentLang)

    const colors = {
        auto: color_choice === "auto",
        ...(color_choice === "light" || color_choice === "auto" && default_scheme === "light") ? LightColors : DarkColors
    }



    return (
        <LanguageContext.Provider value={{lang, setLang}} >
            <ThemeContext.Provider value={colors} >
                <NavigationContainer>     
                    <Tab.Navigator screenOptions={{
                        headerShown: false,
                        tabBarStyle: {display: 'none'},
                    }} >
                        <Tab.Screen name={'Home'}>
                            {(props) => <Home {...props} restartApp={restartApp} />}
                        </Tab.Screen>
                    </Tab.Navigator>
                </NavigationContainer>
            </ThemeContext.Provider>
        </LanguageContext.Provider>
    );
}

选项B

出于性能原因,建议使用上下文而不是上述技巧。文档指出(关于使用

children
):

默认情况下,React Navigation 对屏幕组件进行优化,以防止不必要的渲染。使用渲染回调可以消除这些优化。因此,如果您使用渲染回调,则需要确保对屏幕组件使用 React.memo 或 React.PureComponent 以避免性能问题。

我将避免讨论具体细节,因为创建一个上下文并在其中放入一些东西(如

restartApp
),然后将其从子组件中拉出(如
Home
)是一项常见任务。

您仍然会将

Home
作为一个单独的组件进行分解,但您可以像以前一样使用
component
上的
Tab.Screen
属性来引用它。
Home
将从您创建的包装
restartApp
的新上下文中获得
NavigationContainer

© www.soinside.com 2019 - 2024. All rights reserved.