首页 > 解决方案 > 为什么在导航之前加载我的另一个屏幕?

问题描述

我只使用导航 5。我有启动画面、登录和主选项卡屏幕。我的堆栈已经从启动 --> 登录 --> 主选项卡排序。最终,登录屏幕在启动时首先加载,但屏幕显示启动画面部分。在登录加载时,我将检查与域的连接,问题就出来了Warning: Can't perform a React state update on an unmounted component

导航-container.js

const LoginStack = createNativeStackNavigator();
function NavigatorLogin() {
    return (
        <LoginStack.Navigator>
            <LoginStack.Screen name="AppSignIn" component={AppSignIn} />
            {* .... etc *}
        </LoginStack.Navigator>
    );
}

const MainTabStack = createNativeStackNavigator();
function NavigatorMainTab() {
    return (
        <MainTabStack.Navigator>
            {* .... etc *}
        </SupervisorStack.Navigator>
    );
}

const StackApp = createNativeStackNavigator();
export const AppStackNavigator = () => {
    const [appState, setAppState] = React.useState({});
    const [dataState, setDataState] = React.useState({});
    const [initialRoute, setInitialRoute] = React.useState('NavigatorLogin');
    const state = { appState, setAppState };
    const datas = { dataState, setDataState };
    React.useEffect(() => {
        setAppState({ IsLoading: true, IsLoggedIn: false });
        setDataState({ taskitem: {} });
        console.log('App state 1: ', appState);
    }, []);
    React.useEffect(() => {
        console.log('App state: ', appState);
    }, [appState]);
    return (
        <AppContext.Provider value={state}>
            {appState.IsLoading ? (
                <AppSplash />
            )
                : (
                    <NavigationContainer>
                        <StackApp.Navigator initialRouteName={initialRoute}>
                            {
                                appState.IsLoggedIn
                                    ?
                                    <StackApp.Screen name='NavigatorMainTab' component={NavigatorMainTab}/>
                                    :
                                    <StackApp.Screen name='NavigatorLogin' component={NavigatorLogin}/>
                            }
                        </StackApp.Navigator>
                    </NavigationContainer>
                )}
        </AppContext.Provider>
    )
}

应用登录.js

export const AppSignIn = () => {
    const isMountedRef = React.useRef(false);
    const { appState, setAppState } = React.useContext(AppContext);

    React.useState(() => {
        console.log('Hello from sign in screen; ', appState)
        isMountedRef.current = true;
        if (isMountedRef.current) {
            // check domain connection
        }
        return () => {
            unsubscribe();
            isMountedRef.current = false;
        }
    }, []);
    return (
        <SafeAreaView style={{ flex: 1 }}>
        </SafeAreaView>
    )
}

在终端上显示如下:

     LOG  Running "myproject" with {"rootTag":41}
     LOG  Hello from sign in screen;  {}
     LOG  App state 1:  {}
     LOG  App state:  {}
     ERROR  Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
        in AppSignIn (at SceneView.tsx:126)
        in StaticContainer
        in EnsureSingleNavigator (at SceneView.tsx:118)
        in SceneView (at useDescriptors.tsx:209)
        in RCTView (at View.js:32)
        in View (at DebugContainer.native.tsx:27)
        in DebugContainer (at NativeStackView.native.tsx:71)
        in MaybeNestedStack (at NativeStackView.native.tsx:229)
        in RNSScreen (at createAnimatedComponent.js:243)
        in AnimatedComponent (at createAnimatedComponent.js:296)
        in AnimatedComponentWrapper (at src/index.native.tsx:169)
        in Screen (at NativeStackView.native.tsx:175)
        in SceneView (at NativeStackView.native.tsx:277)
        in RNSScreenStack (at NativeStackView.native.tsx:268)
        in NativeStackViewInner (at NativeStackView.native.tsx:322)
        in RCTView (at View.js:32)
        in View (at SafeAreaProviderCompat.tsx:42)
        in SafeAreaProviderCompat (at NativeStackView.native.tsx:321)
        in NativeStackView (at createNativeStackNavigator.tsx:67)
        in NativeStackNavigator (at navigation-container.js:20)
        in NavigatorLogin (at SceneView.tsx:126)
        in StaticContainer
        in EnsureSingleNavigator (at SceneView.tsx:118)
        in SceneView (at useDescriptors.tsx:209)
        in RCTView (at View.js:32)
        in View (at DebugContainer.native.tsx:27)
        in DebugContainer (at NativeStackView.native.tsx:71)
        in MaybeNestedStack (at NativeStackView.native.tsx:229)
        in RNSScreen (at createAnimatedComponent.js:243)
        in AnimatedComponent (at createAnimatedComponent.js:296)
        in AnimatedComponentWrapper (at src/index.native.tsx:169)
        in Screen (at NativeStackView.native.tsx:175)
        in SceneView (at NativeStackView.native.tsx:277)
        in RNSScreenStack (at NativeStackView.native.tsx:268)
        in NativeStackViewInner (at NativeStackView.native.tsx:322)
        in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
        in SafeAreaProvider (at SafeAreaProviderCompat.tsx:46)
        in SafeAreaProviderCompat (at NativeStackView.native.tsx:321)
        in NativeStackView (at createNativeStackNavigator.tsx:67)
        in NativeStackNavigator (at navigation-container.js:72)
        in EnsureSingleNavigator (at BaseNavigationContainer.tsx:430)
        in BaseNavigationContainer (at NavigationContainer.tsx:132)
        in ThemeProvider (at NavigationContainer.tsx:131)
        in NavigationContainerInner (at navigation-container.js:71)
     LOG  App state:  {"IsLoading": true, "IsLoggedIn": false, "IsSupervisor": false}
     LOG  splash info here
     LOG  Hello from sign in screen;  {"IsLoading": false}
     LOG  App state:  {"IsLoading": false}

最初我没有使用useRef。我使用它作为发现类似的问题,但它仍然错误。我也使用如下功能,但仍然有错误。我不确定其他选项或如何判断我的问题的正确词是什么。

function useIsMountedRef() {
    const isMountedRef = React.useRef(null);
    React.useEffect(() => {
        isMountedRef.current = true;
        return () => isMountedRef.current = false;
    }, []);
    return React.useCallback(() => isMountedRef.current, []);
}

.
.
.
const isMountedRef = useIsMountedRef();

标签: react-nativereact-navigation-v5

解决方案


经过几天的搜索和尝试错误,终于警告消失了。

由于我使用上下文 API 来替换切换导航器,因此我使用上下文而不是isMountedRef在挂载上进行检查。

删除旧代码

编辑:通过在屏幕安装上进行变量检查,这是绝对不合适的,因为当与服务器的连接失败时计时器将不会运行。解决方案在于navigation-container.js

/// This is original from first post
const [appState, setAppState] = React.useState({});

/// I change to this
const [appState, setAppState] = React.useState({ IsLoading: true, IsLoggedIn: false });

我的 AppSignIn.js

React.useEffect(() => {
    console.log('Login screen mounted');
    const unsubscribe = NetInfo.addEventListener(async state => {
        setIsPhoneConnected(state.isConnected);
        console.log('Phone connected? ' + state.isConnected + ', Server connected? ' + IsServerConnected)
    });
    
  CheckServerConnection()
       .then((response) => {
           console.log(response);
           setIsServerConnected(true);
       })
       .catch((error) => {
           setIsServerConnected(false);
           ResetTimer(5);
       });
    return () => {
        unsubscribe();
    }
}, []);

推荐阅读