【问题标题】:Remembering state before app goes in foreground在应用程序进入前台之前记住状态
【发布时间】:2021-06-07 10:14:36
【问题描述】:

我有一个 react native 项目,我必须实现一个功能,当应用程序处于非活动状态时,它会呈现一个徽标屏幕,而当应用程序处于活动状态时,它会呈现应用程序。

我能够做到这一点,但我现在的问题是。如果我的主屏幕是主屏幕,并且当我在我的应用程序和另一个应用程序之间导航时我当前在我的个人资料屏幕上,然后返回我的应用程序,我会返回主屏幕而不是个人资料屏幕。

我该如何解决这个问题?

我应该将应用的当前状态保存在 AsyncStorage 中吗?

我也在使用 React Context API 而不是 redux。

这是我要求的代码:

const[isReady, setIsReady] = useState(false);
const[user,setUser]=useState();
const[authenticated,setAuthenticated]=useState();
const appState = useRef(AppState.currentState);
const [appStateVisible, setAppStateVisible] =useState(appState.current);

const _handleAppStateChange = (nextAppState) => {
if (
  appState.current.match(/inactive|background/) &&
  nextAppState === "active"
) {
  console.log("App has come to the foreground!");
}

appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log("AppState", appState.current);
};

 useEffect(() => {
 AppState.addEventListener("change", _handleAppStateChange);
  return () => {
  AppState.removeEventListener("change", _handleAppStateChange);
  };
  }, []);

const restoreUser = async () => {
const user = await storage.getUser();
if (user) setUser(user);
};

if (!isReady)
return (
<AppLoading 
startAsync={restoreUser} 
onFinish={() => setIsReady(true)} 
onError={console.warn}
/>
);  

return(
 (appState.current)==='active'?
 <AuthContext.Provider value= 
 {{user,setUser,authenticated,setAuthenticated}}>
 <NavigationContainer theme={navigationTheme} ref={navigationRef}>
   {
   (user&&authenticated)?<AppNavigator/>
   :(user)?<PasscodeNavigator/>
   :<AuthNavigator/>
   }
 </NavigationContainer>
 </AuthContext.Provider>
 :
 <SplashScreen/>

【问题讨论】:

  • 我删除了我的答案,因为它不是答案。这只是一个一般性建议,如果您不显示一些代码,我认为任何人都无法提供帮助。我认为我个人无法提供帮助,因为我使用 react-native 已经有一段时间了,但也许我可以建议我会看的东西。我会记录经过身份验证的用户状态,看看它们是否符合您的期望。如果它们不是您所期望的,那么您可能希望将它们存储在 localstorage 或 redux 中。
  • 正如@howtopythonpls 建议的调查身份验证状态,似乎没有任何类似于 restoreUser 的 setAuthenticated 并且我猜你显示配置文件的条件都是(用户 && 身份验证)。
  • @agenthunt 嗨,感谢您回复我。我的身份验证状态用于检查是否存在用户令牌,而不是呈现我的欢迎屏幕,而是呈现我的密码屏幕。目前我的身份验证状态正常工作,我的问题是当我实现上述代码时。假设我在设置屏幕上并转到另一个应用程序然后返回不返回设置屏幕我返回我的提要屏幕。
  • 在不知道细节的情况下很难弄清楚你的应用程序路由结构。再次在黑暗中拍摄。您的路线可能未保存,或者您的应用需要在哪个路线上派生的状态未保存或未正确派生以使恢复恢复到正确的屏幕?
  • @agenthunt 在 Tab Navigator 组件中我指定了我的初始路线名称作为我的提要屏幕,这也许是为什么我从前台来后我降落在那里?您需要什么信息?

标签: javascript react-native


【解决方案1】:

当应用状态改变时,您可以在模式而不是屏幕中显示/隐藏 Splash

import {  Modal } from "react-native";

const [modalVisible, setModalVisible] = useState(false);

const _handleAppStateChange = nextAppState => {
  if (
    appState.current.match(/inactive|background/) &&
    nextAppState === 'active'
  ) {
    setModalVisible(false);
  } else {
    setModalVisible(true);
  }
};


return (
  <>
    <AuthContext.Provider
      value={{ user, setUser, authenticated, setAuthenticated }}
    >
      <NavigationContainer theme={navigationTheme} ref={navigationRef}>
        {user && authenticated ? (
          <AppNavigator />
        ) : user ? (
          <PasscodeNavigator />
        ) : (
          <AuthNavigator />
        )}
      </NavigationContainer>
    </AuthContext.Provider>
    <Modal animationType="slide" transparent={true} visible={modalVisible}>
      <SplashScreen />
    </Modal>
  </>
);

【讨论】:

  • 我刚刚尝试了您提供的代码,但它仍然无法正常工作,当我进入前台时不会发生。我应该在我提供的代码中添加 useEffect 吗?
  • 我想我应该把 放在我的 NavigationContainer 中
【解决方案2】:

我看到了您的问题,您还有另一种选择,除了在 AsyncStorage 中保存状态之外,您可以将所有应用程序包装在一个导航容器中并使用导航引用进行重定向。

示例:


const { StyleSheet } = require('react-native');

const App = () =>{
  const[isReady, setIsReady] = useState(false);
const[user,setUser]=useState();
const[authenticated,setAuthenticated]=useState();
const appState = useRef(AppState.currentState);
const [appStateVisible, setAppStateVisible] =useState(appState.current);

const _handleAppStateChange = (nextAppState) => {
if (
  appState.current.match(/inactive|background/) &&
  nextAppState === "active"
) {
  console.log("App has come to the foreground!");
}

appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log("AppState", appState.current);
};

 useEffect(() => {
 AppState.addEventListener("change", _handleAppStateChange);
  return () => {
  AppState.removeEventListener("change", _handleAppStateChange);
  };
  }, []);

const restoreUser = async () => {
const user = await storage.getUser();
if (user) setUser(user);
};

if (!isReady)
return (
<AppLoading 
startAsync={restoreUser} 
onFinish={() => setIsReady(true)} 
onError={console.warn}
/>
);  

return(
 
 <AuthContext.Provider value= 
 {{user,setUser,authenticated,setAuthenticated}}>
 <NavigationContainer theme={navigationTheme} ref={navigationRef}>
   {
   (user&&authenticated)?<AppNavigator/>
   :(user)?<PasscodeNavigator/>
   :<AuthNavigator/>
   }
 </NavigationContainer>
 { (appState.current)!=='active' && <View style={StyleSheet.absoluteFillObject}><SplashScreen/></View> }
 </AuthContext.Provider>
)
}

【讨论】:

  • 嗨,迈克,我刚刚尝试了您的解决方案,但它不起作用,启动画面是唯一渲染的屏幕
猜你喜欢
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多