Home > OS >  How to show a screen only on first time use?
How to show a screen only on first time use?

Time:05-05

I am trying to show the license agreement screen only once. On that screen, there is an ACCEPT button, once clicked - it saved a value to AsyncStorage.

In app.js I then check the value of that key in AsyncStorage and act accordingly. My problem is that the Login screen keeps showing first when I expect the License agreement to.

I think it's an async issue but not sure how to resolve it.

I did try initially set loading to true in the useState, and this method works. But once I accept the agreement the first time and then reload the app - I see the license agreement screen for a quick second before it redirects to the login screen - not ideal.

The console log prints the value as expected, but I think the navigation renders before useEffect logic is complete.

App.js

function App() {


const [loading, setLoading] = useState(false);

  useEffect(() => {
    load();
  }, []);

  const load = async () => {
    await AsyncStorage.getItem('isAgreementAccepted').then(result => {
      console.log('RES: ', result)
        if (result == null) {
           setLoading(true);

        } else {
           setLoading(false);
        }
    })

}

  return (
    <NavigationContainer>
      <Stack.Navigator> 
         {loading && <Stack.Screen
          name="EndUserAgreement"
          component={EndUserAgreementScreen}
          options={{ headerShown: false }}
        />}
         <Stack.Screen
          name="Login"
          component={LoginScreen}
          options={{ headerShown: false }}
        />

CodePudding user response:

like you say, you're Stack.screens are rendering before the loading state is set, so you're login screen loads on it's own, then once loading is set to true your endUserAgreement screen is loading in - but your navigation (react-navigation?) won't automatically switch your route

you can:

  • navigate to the endUserAgreement screen using the useNavigation hook & .navigate() (render both Stack.screens in this scenario, and set the initialRouteName on the Stack.Navigator to 'login')

  • leave only the endUserAgreement screen in place if the storage call returns null, which will force the navigation to only show that screen - something like:

{loading ? (
  <Stack.Screen
    name="EndUserAgreement"
    component={EndUserAgreementScreen}
    options={{ headerShown: false }}
  />
) : ( 
  <Stack.Screen
    name="Login"
    component={LoginScreen}
    options={{ headerShown: false }}
  />
  {/* ... other screens here */}
)}
  • show a loading screen until your storage call is complete, then set the initialRouteName based on it's outcome:
const [loading, setLoading] = useState(null)

const load = async () => {
    await AsyncStorage.getItem('isAgreementAccepted').then(result => {
      console.log('RES: ', result)
        if (result == null) {
           setLoading(true);
        } else {
           setLoading(false);
        }
    })

}

  return (
    <NavigationContainer>
       
      {loading === null ? (
        <LoadingScreen />
      ) : (
        <Stack.Navigator initialRouteName={loading ? 'EndUserAgreement' : 'login'}>
         <Stack.Screen
          name="EndUserAgreement"
          component={EndUserAgreementScreen}
          options={{ headerShown: false }}
        />}
         <Stack.Screen
          name="Login"
          component={LoginScreen}
          options={{ headerShown: false }}
        />

so we're defaulting to null loading state, showing a loading component until it's set to true or false, then setting the initial route name to the correct screen name.

CodePudding user response:

What you need to do here is render the screen normally inside Stack.Navigator.

And once you get a positive value to know that it is the first time the user opens the application, you must navigate to that screen normally, as shown in the following code:

import { useNavigation } from '@react-navigation/native';

function App() {


  const [loading, setLoading] = useState(false);
  const navigation = useNavigation();

  useEffect(() => {
    load();
  }, []);

  const load = async () => {
    await AsyncStorage.getItem('isAgreementAccepted').then(result => {
      console.log('RES: ', result)
        if (result == null) {
            navigation.navigate('EndUserAgreement');
            await setLocalStoreData('isAgreementAccepted', 'true');
        }
    });
  }

  return (
    <NavigationContainer>
      <Stack.Navigator> 
         <Stack.Screen
          name="EndUserAgreement"
          component={EndUserAgreementScreen}
          options={{ headerShown: false }}
        />
         <Stack.Screen
          name="Login"
          component={LoginScreen}
          options={{ headerShown: false }}
        />
  • Related