【问题标题】:React Navigation - remove components from navigation state and navigate to ScreenReact Navigation - 从导航状态中移除组件并导航到 Screen
【发布时间】:2021-04-06 10:33:54
【问题描述】:

我在我的 React Native 应用程序中使用 React Navigation 作为路由器。我有一个问题,即当我在屏幕之间导航时,之前在我们之前渲染的屏幕时创建的钩子仍然存在。

我有一个完全扁平的路由器:

const AppRouter = () => {
    const Stack = createStackNavigator();

    return (
        <NavigationContainer ref={navigationRef}>
            <Stack.Navigator headerMode={false}>
                <Stack.Screen
                    component={Landing}
                    name="Landing"
                    options={fadeAnimation}
                />
                <Stack.Screen
                    component={LogInOrSignUp}
                    name="LogInOrSignUp"
                    options={fadeAnimation}
                />
                <Stack.Screen
                    component={Dashboard}
                    name="Dashboard"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={Loader}
                    name="Loader"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={WakingFromKilled}
                    name="Connecting"
                />
                <Stack.Screen
                    component={EnterPhoneNumber}
                    name="EnterPhoneNumber"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={EnterSmsCode}
                    name="EnterSmsCode"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={CompleteProfile}
                    name="CompleteProfile"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={Contacts}
                    name="Contacts"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={TimeInput}
                    name="TimeInput"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={InCallContainer}
                    name="InCallContainer"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={ConnectingController}
                    name="ConnectingController"
                    options={horizontalAnimation}
                />
                <Stack.Screen
                    component={AccountModal}
                    name="AccountModal"
                />
                <Stack.Screen
                    component={NoInternetConnection}
                    name="NoInternetConnection"
                    options={horizontalAnimation}
                />
            </Stack.Navigator>
        </NavigationContainer>
    );
};

当我从Dashboard &gt; TimeInput &gt; InCallContainer &gt; Dashboard &gt; TimeInput &gt; InCallContainer 导航时,第一次访问时在InCallContainer 中创建的钩子在第二次访问时仍然存在。

我正在使用以下方法导航:

import { StackActions } from '@react-navigation/native';
import * as React from 'react';

export const navigationRef = React.createRef();

export function navigate(...args) {
    navigationRef.current.navigate(...args);
}

然后:

RootNavigation.navigate('InCallContainer');

我可以看出钩子被创建了多次,因为如果我在使用这些钩子的组件中登录,每次我导航到它们时,我都会得到一个更多的日志。所以当我第二次访问屏幕时有两个日志,依此类推。

我希望能够第二次导航到仪表板,当我这样做时,从内存中卸载/删除此导航之前的所有组件。

我尝试过替换、重置、推送、popToTop,但都没有达到预期的效果。

我怎样才能做到这一点?

TIA

更新:

我需要从 Redux Thunk 内部以编程方式导航到 InCallContainer

export const answerCall = (calleeName) => (dispatch, getState) => {
    const { session, callType } = getState().callData;
    acceptCall(session, { calleeNameFromOwnContacts: calleeName });
    dispatch(callData({ callState: INCOMING }));
    stopRingtone();
    RootNavigation.navigate('InCallContainer');
    InCallManager.start({ media: callType === VIDEO ? 'video' : 'audio' });
    InCallManager.turnScreenOn();
};

【问题讨论】:

    标签: react-native react-navigation


    【解决方案1】:

    屏幕 InCallContainer 尚未卸载,当我们要在同一个导航器中使用相同的键打开屏幕时,它不会重新渲染它共享它的实例,所以如果你要用它的钩子重新渲染它,然后你必须创建单独的导航器。

    【讨论】:

    • 好的,谢谢@Jignesh - 你能提供一个我应该如何做的简单例子吗?此外,如果我在导航到该组件时不想要相同的组件实例,这是否也包括所有子组件?
    • 您想如何实现屏幕导航,因为这里我们必须创建一个单独的导航器?
    • 每次导航到“InCallContainer”时,它都必须是该组件的全新实例,并且每个子组件和挂钩都必须是全新的实例
    • 实际上,我在问您希望如何导航到 InCallContainer 屏幕以及您要从哪个其他屏幕导航到 InCallContainer 屏幕?
    • 啊,我明白了!好吧,我需要能够从 Redux Thunk 以编程方式导航到 InCallContainer - 我已经用更多代码更新了这个问题 - 非常感谢。
    【解决方案2】:

    使用navigate 路由已经在导航历史中的路线不要创建新路线,它只是导航到它。
    您需要使用push 而不是navigate 作为RootNavigation.push('InCallContainer')

    push 将创建新路线。

    阅读Navigate to a route multiple times

    此示例显示pushnavigate 之间的差异尝试零食here

    • 使用navigate时访问次数增加+1
    • 但使用push以首次访问时间开始新路线。

    代码:

    import 'react-native-gesture-handler';
    import * as React from 'react';
    import { Button, View, Text } from 'react-native';
    import { NavigationContainer } from '@react-navigation/native';
    import { createStackNavigator } from '@react-navigation/stack';
    
    
    
    function HomeScreen({ navigation }) {
    
        const [visitTimes, setVisitTimes] = React.useState(0);
    
        React.useEffect(() => {
            const unsubscribe = navigation.addListener('focus', () => {
                setVisitTimes(v => v + 1);
            });
    
            return unsubscribe;
        }, [navigation]);
    
    
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Home visitTimes :</Text>
                <Text style={{padding: 20, fontSize : 80, fontWeight : "700"}}>{visitTimes}</Text>
                <Button
                    title="push"
                    onPress={() => navigation.push('Details')}
                />
            </View>
        );
    }
    
    
    
    
    
    function DetailsScreen({ navigation }) {
    
    
        const [visitTimes, setVisitTimes] = React.useState(0);
    
    
        React.useEffect(() => {
            const unsubscribe = navigation.addListener('focus', () => {
                setVisitTimes(v => v + 1);
            });
    
            return unsubscribe;
        }, [navigation]);
    
    
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Details visitTimes :</Text>
                <Text style={{padding: 20, fontSize : 80, fontWeight : "700"}}>{visitTimes}</Text>
                <Button
                    title="navigate"
                    onPress={() => navigation.navigate('Home')}
                />
            </View>
        );
    }
    
    const Stack = createStackNavigator();
    
    function App() {
        return (
            <NavigationContainer>
                <Stack.Navigator initialRouteName="Home">
                    <Stack.Screen name="Home" component={HomeScreen} />
                    <Stack.Screen name="Details" component={DetailsScreen} />
                </Stack.Navigator>
            </NavigationContainer>
        );
    }
    
    export default App;
    
    

    【讨论】:

      【解决方案3】:

      我不确定您使用的是什么钩子,但 React Navigation 确实为生命周期事件公开了自己的钩子。

      替换传统 useEffect 钩子的示例:

      import { useFocusEffect } from '@react-navigation/native';
      
      function Profile() {
        useFocusEffect(
          React.useCallback(() => {
            // Do something when the screen is focused
      
            return () => {
              // Do something when the screen is unfocused
              // Useful for cleanup functions
            };
          }, [])
        );
      
        return <ProfileContent />;
      }
      

      只有当你导航到组件并且它在 React Navigation 的上下文中成为“焦点”时才会触发。 React Navigation 尝试提前挂载所有视图以提高性能,这就是为什么传统的 React 挂钩可能会导致问题与 React Navigation 公开的焦点样式相比。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-17
        • 1970-01-01
        • 2017-09-10
        • 2021-08-19
        • 1970-01-01
        • 2018-12-01
        • 2018-04-08
        • 2017-11-29
        相关资源
        最近更新 更多