Houston, we have a problem.
I never quite understood how Redux works. When the time came to do the authentication flow for my react native app, I found a tutorial that used a reducer, copied it, and it worked... It was always very confusing to me why the code worked since I don't see where I pass in the "loginState" variable into the context... but it was working (on ios) so I let it be.
But today, as I was trying the web version of the react native app it became a problem. For some reason I dont understand either, it is acceptable to declare a variable without the "const" in react native ios/android but not web. If to fix that i declare the redux state with type declaration (like shown here) it is not available to nested functions anymore:
**const** [loginState, dispatch] = React.useReducer(LoginReducer, {isLoading: false, isSignout: false, userToken: null, isVerified: false})
Please please please help me understand
Here is my App.js:
import * as React from 'react';
import LoginReducer from './Reducer/LoginReducer';
import AppContainer from './Navigators/AppNavigationContainer.js'
import {loadLocale, strings2} from './assets/locales/i18n'
import {AppLoading} from 'expo'
global.AuthContext = React.createContext();
global.LanguageContext = React.createContext({
language: 'es',
setLanguage:()=>{}
})
export default function App ({navigation}) {
//LanguageContext
const [languageReady, setLanguageReady] = React.useState(false);
const [language,setLanguage] = React.useState('es');
//Load language
const initLang = async () => {
const currentLanguage = await loadLocale()
setLanguage(currentLanguage)
};
[loginState, dispatch] = React.useReducer(LoginReducer, {isLoading: false, isSignout: false, userToken: null, isVerified: false})
global.authContext = React.useMemo(() => ({
signIn: () => {
dispatch({ type: 'SIGN_UP' })
dispatch({ type: 'SIGN_IN', token: 'dummy-token' });
AsyncStorage.setItem('userToken', 'dummy-token' )
},
signOut: () => {
AsyncStorage.removeItem('userToken')
dispatch({ type: 'SIGN_OUT' })
},
signUp: () => {
dispatch({ type: 'SIGN_IN', token: 'dummy-token' })
AsyncStorage.setItem('userToken', 'dummy-token')
},
}),[]);
return(
<>
{languageReady ? (
<LanguageContext.Provider value={{language, setLanguage}}>
<AppContainer/>
</LanguageContext.Provider>
) : (
<AppLoading
startAsync={initLang()}
onFinish={setLanguageReady(true)}/>
)}
</>
)
}
And here is my App Navigator where the redux state "loginState" should be available to do the authentication flow.
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import LoadingScreen from '../Screens/LoadingScreen.js'
import SignInScreen from '../Screens/SignInScreen.js'
import VerifyEmail from '../Screens/VerifyEmail.js'
import MainAppTab from './MainAppTab.js'
const Stack = createStackNavigator();
export default function AppContainer () {
return (
<AuthContext.Provider value={global.authContext}>
<NavigationContainer>
<Stack.Navigator
initialRouteName='SignIn'
headerMode='none'
>
{loginState.isLoading ? (<>
<Stack.Screen name='Loading' component={LoadingScreen}/>
</>) : loginState.userToken == null ? (<>
<Stack.Screen name='SignIn' component={SignInScreen}/>
</>) : loginState.isVerified === false ? (<>
<Stack.Screen name='Verify' component={VerifyEmail}/>
</>) : (
<Stack.Screen name='Main' component={MainAppTab}/>
)}
</Stack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
)
}