this is the first app where I work with react native and expo. this is
"expo": "~49.0.13",
"react-native": "0.72.6",
"@react-navigation/drawer": "^6.6.5",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.15",
I'm having a very strange problem with my application.
I have a global state of the application created with useContext.
import { UserState } from '@models/userModel';
import React, { createContext, useReducer } from 'react';
const initialState: UserState = {
isAuthenticated: false,
userData: null
};
export type TypeContext = {
state: UserState,
dispatch: React.Dispatch<any>;
};
const UserContext = createContext<TypeContext>({
state: initialState,
dispatch: () => { }
});
const { Provider } = UserContext;
type Props = {
children: any;
};
type Actions =
| {
type: 'set_user',
userData: any;
}
|{
type: 'is_authenticated',
isAuthenticated: boolean
}
| {
type: 'delete_user'
}
| {
type: 'update_user',
userData: any
};
export enum TypesInContext {
set_user = 'set_user',
is_authenticated = 'is_authenticated',
delete_user = 'delete_user',
update_user = 'update_user'
};
const reducer = (state: UserState, action: Actions): UserState =>{
switch (action.type) {
case TypesInContext.set_user:
return{
...state,
userData: action.userData,
};
case TypesInContext.is_authenticated:
console.log("ACCCCTIOOON--->",action)
return {
...state,
isAuthenticated: action.isAuthenticated
}
case TypesInContext.delete_user:
return{
...state,
userData: null,
isAuthenticated: false
}
case TypesInContext.update_user:
return {
...state,
userData: action.userData
}
default:
return state;
}
};
const UserProvider = ({children}:Props) =>{
const [state,dispatch]= useReducer(reducer,initialState);
return <Provider value={{state,dispatch}}>{children}</Provider>
};
export {UserContext,UserProvider}
I use this status in my index to be able to switch screens. Obviously I wrap my app with the context as indicated in the documentation.
import { StatusBar } from 'expo-status-bar';
import Index from './src/Index';
import 'react-native-gesture-handler';
import { UserProvider } from '@src/store/userContext';
export default function App() {
return (
<UserProvider>
<StatusBar style='auto'/>
<Index />
</UserProvider>
);
}
and use here
import React, { useContext } from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationContainer } from '@react-navigation/native';
import LoginScreen from '@screens/LoginScreen';
import { RootTypesNavigation } from '@navigation/typesNavigation';
import DrawerNavigation from '@navigation/DrawerNavigation';
import { UserContext } from './store/userContext';
export default function Index() {
const Stack = createNativeStackNavigator<RootTypesNavigation>();
const { state } = useContext(UserContext);
console.log("🚀 ~ file: Index.tsx:11 ~ Index ~ state:", state)
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='Login'>
{state.isAuthenticated ?
<Stack.Screen name='DrawerNavigation' component={DrawerNavigation} options={{ headerShown: false }} />
:
<Stack.Screen name='Login' component={LoginScreen} options={
{ headerShown: false }
} />
}
</Stack.Navigator>
</NavigationContainer>
);
}
and the state in this particular case, we alter it from LoginScreen in these functions (I did a little demo here)
const submitLogin = async () => {
if (!isEmailValid(email)) {
notifyMessage('Error', "El email ingresado no es válido.")
return;
}
let objetAuthetication: ParametersLogin = {
username: email,
password: password,
domain: domain,
deviceInfo: {
available: true,
platform: Device.osName,
version: Device.osVersion,
uuid: null,
cordova: "react-native 0.72.6",
model: domain,
manufacturer: Device.brand,
isVirtual: false,
serial: null,
appVersion: "1.0.11"
}
}
const response = await authLogin(objetAuthetication);
if (response && response.status == 'OK') {
setAlertLoginOk(true);
dispatch({
type: TypesInContext.set_user,
userData: response.result,
})
} else {
alertAccessDenied();
}
}
by business logic, first I have to do a dispatch to save the user data, and then in another confirmation I do the dispatch of the isAuthenticated, where here I alter the state where it shows one screen or another.
const emailConfirmationAndAuthentication = async () => {
if (newEmail) {
console.log("Se registro nuevo email");
//Que hacer aca? Update? en la web no hace nada.
};
setAlertLoginOk(false);
console.log("🚀 ~ file: LoginScreen.tsx:78 ~ emailConfirmationAndAuthentication ~ navigation:", navigation)
// navigation.navigate('DrawerNavigation',{screen:'Home'})
setTimeout(()=>{
dispatch({
type: TypesInContext.is_authenticated,
isAuthenticated: true
});
},1000)
};
that horrible setTimeOut was the solution for my app not to break (thanks to a thread in this community), but I really want to understand what is going on or what is the error that occurs or what am I doing wrong.
Did anyone come across this? Am I doing something wrong? What is the problem? Did I miss some of the documentation?
I've been having these problems for several days now and I don't understand! Thank you very much!
luckily I was able to find the problem. It was the react-navigation/native-stack library. I changed that library, for react-navigation/stack and all my problems with the state have been solved. I hope this is helpful for someone.