为什么在导航之前加载了我的其他屏幕?
Why my other screen is loaded before navigate?
我只使用导航 5。我有启动画面、登录画面和主选项卡画面。我的堆栈已经从 splash --> login --> main 选项卡排序。最终,登录屏幕在启动时首先加载,但屏幕显示启动画面部分。在登录加载时,我将检查与域的连接,问题出来告诉 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>
)
}
AppSignIn.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();
经过几天的搜索和尝试错误,终于警告消失了。
因为我使用上下文 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();
}
}, []);
我只使用导航 5。我有启动画面、登录画面和主选项卡画面。我的堆栈已经从 splash --> login --> main 选项卡排序。最终,登录屏幕在启动时首先加载,但屏幕显示启动画面部分。在登录加载时,我将检查与域的连接,问题出来告诉 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>
)
}
AppSignIn.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();
经过几天的搜索和尝试错误,终于警告消失了。
因为我使用上下文 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();
}
}, []);