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 }}
/>
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.screen
s 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 */}
)}
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.