store.ts
import { configureStore, getDefaultMiddleware, CaseReducer} from '@reduxjs/toolkit';// import { loginUser } from './slices/auth';// import { createStore } from 'redux';// import loginScreen from './slices/auth';import { combineReducers } from 'redux';import { authApi, useLoginUserMutation } from './api/authApi';import authSlice, { loginUser } from './slices/updatedAuth';import auth, { loginUser as loginUser2 } from './slices/auth';import { loginRequest } from '../types/auth';export type type_1 = { initial: boolean, test: string}let initialCustomState: type_1 = { initial: false, test: "abc"};const rootReducer = combineReducers({ [authApi.reducerPath]: authApi.reducer});// const store = configureStore({// reducer: { rootReducer },// middleware: (getDefaultMiddleware) =>// getDefaultMiddleware().concat(authApi.middleware)// });const store = configureStore({ reducer: { authSlice: authSlice }, // middleware: (getDefaultMiddleware) => // getDefaultMiddleware().concat(authApi.middleware),})// Infer the `RootState` and `AppDispatch` types from the store itselfexport type RootState = ReturnType<typeof store.getState>;// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}export type AppDispatch = typeof store.dispatch;export default store;// store.dispatch(authApi.endpoints.loginUser({ email: "abc", password: "avc" }));
authslice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';import { loginRequest } from '../../types/auth';import { authApi } from '../api/authApi';import { TimeZone, user } from '../../types/user';type authState = { authToken: string, userKey: string, user: user | null,}let initialState: authState = { authToken: '', userKey: '', user: null,}export const authSlice = createSlice({ name: 'authInfo', initialState, reducers: { loginUser: (state: authState, action: PayloadAction<loginRequest>) => { state.authToken = action.payload.email; }, setUserDetails: (state: authState, action: PayloadAction<user>) => { state.authToken = action.payload.auth_token; state.userKey = action.payload.user_key; state.user = action.payload; }, resetAuth: (state: authState, action: PayloadAction<void>) => { state.user = null; state.authToken = ''; }, setAuthToken : (state : authState, action : PayloadAction<string>) => { state.authToken = action.payload; } }, extraReducers: (builder) => { builder.addMatcher(authApi.endpoints.loginUser.matchPending, (state, action) => { console.log('pending', action); console.log(state); }) .addMatcher(authApi.endpoints.loginUser.matchFulfilled, (state, action) => { console.log('fulfilled', action); state.authToken = action.payload.auth_token; state.user = action.payload; state.userKey = action.payload.user_key; console.log("updated state" , state); }) .addMatcher(authApi.endpoints.loginUser.matchRejected, (state, action) => { console.log('rejected', action); }); },});export default authSlice.reducer;export const { loginUser, setUserDetails, resetAuth, setAuthToken } = authSlice.actions;
stackNavigator.tsx
const Stack = createNativeStackNavigator();const getData = async () => { try { const jsonValue = await AsyncStorage.getItem('logged_in_user') console.log(jsonValue); return jsonValue != null ? JSON.parse(jsonValue) : null; } catch(e) { // error reading value } }export default function StackNavigator() { let state = store.getState(); const dispatch = useAppDispatch(); let [isLoading, setIsLoading] = useState(true); let [authToken, setAuthToken] = useState(state.authSlice.authToken); let [isSignedIn, setIsSignedIn] = useState(false); useEffect( () => { getData().then(res => { console.log(res); if(res !== null) { setIsLoading(false); setAuthToken(res.auth_token); dispatch(authSlice.actions.setAuthToken(res.auth_token)); setIsSignedIn(true); } else { setIsLoading(false); setAuthToken(''); setIsSignedIn(false); } }).catch(err => { console.log(err); setIsLoading(false); setAuthToken(''); setIsSignedIn(false); }) }); if(isLoading) { return <FirstScreen></FirstScreen> } else { return (<Stack.Navigator><> { store.getState().authSlice.authToken !== '' ?<Stack.Screen name = "Drawer" component={DrawerNavigator} options = {{headerShown : false}}></Stack.Screen> :<> <Stack.Screen name = "Login" component = {LoginScreen} options={{headerShown : false}} ></Stack.Screen><Stack.Screen name = "ForgotPassword" component = {ForgotPasswordScreen} options = {{headerShown : false}}></Stack.Screen></> }</></Stack.Navigator> ); }}
App.tsx
import 'react-native-gesture-handler';import { StatusBar } from 'expo-status-bar';import React from 'react';import {View} from 'react-native'import { createAppContainer, StackRouter } from 'react-navigation'import { createDrawerNavigator, DrawerItem, DrawerScreenProps } from '@react-navigation/drawer';import { NavigationContainer, useNavigation } from '@react-navigation/native';import { MaterialCommunityIcons } from '@expo/vector-icons';import { Feather } from '@expo/vector-icons';import { FontAwesome5 } from '@expo/vector-icons';import useCachedResources from './hooks/useCachedResources';import useColorScheme from './hooks/useColorScheme';import Navigation from './navigation';import DrawerItems from './constants/DrawerItems';import store from './src/redux/store';import { Provider } from 'react-redux';import AccountScreen from './screens/AccountScreen';import AlarmsScreen from './screens/AlarmsScreen';import TasksScreen from './screens/TasksScreen';import SupportScreen from './screens/SupportScreen';import LoginScreen from './screens/LoginScreen';import Header from './screens/Header';import SafeAreaProvider from 'react-native-safe-area-context';import { createNativeStackNavigator } from '@react-navigation/native-stack';import ForgotPasswordScreen from './screens/ForgotPasswordScreen';import AsyncStorage from '@react-native-async-storage/async-storage';import { authApi, useLoginUserMutation } from './src/redux/api/authApi';import DrawerNavigator from './src/navigators/drawerNavigator';import { authSlice } from './src/redux/slices/updatedAuth';import StackNavigator from './src/navigators/stackNavigator';const Drawer = createDrawerNavigator();const Stack = createNativeStackNavigator();export default function App() { const state = store.getState(); return (<NavigationContainer><Provider store={store}><StackNavigator></StackNavigator></Provider></NavigationContainer> );}
LoginScreen.tsx
import React, {useState} from 'react'import { StyledButton, StyledTextInput, Logo, Header, Background, setDataInAsyncStorage} from '../src/utils/utils'import {Text, View, TouchableOpacity} from 'react-native'import { emailValidator } from './../src/validators/emailValidator';import { passwordValidator } from './../src/validators/passwordValidator';import { styles } from './../src/styles/styles';import { Navigation } from '../src/types/genericTypes';import { useLoginUserMutation } from '../src/redux/api/authApi';import {Snackbar} from 'react-native-paper'import AsyncStorage from '@react-native-async-storage/async-storage';import { authSlice, setAuthToken } from './../src/redux/slices/updatedAuth';import { useAppDispatch } from './../src/redux/hooks';import { useDispatch } from 'react-redux';import { getErrorMessageFromErrorListDTOResponse } from '../src/utils/utils';type Props = { navigation : Navigation;}const LoginScreen = ({navigation} : Props) => { const [email, setEmail] = useState({value : '', error : ''}); const [password, setPassword] = useState({value : '', error : ''}); const [loginUser, {isLoading, isError}] = useLoginUserMutation(); const [error, setError] = useState(''); const [visible, setVisible] = useState(false); const dispatch = useAppDispatch(); const onDismissSnackBar = () => { setVisible(false); } const _onLoginPressed = () => { const emailError = emailValidator(email.value); const passwordError = passwordValidator(password.value); if (emailError || passwordError) { setEmail({ ...email, error: emailError }); setPassword({ ...password, error: passwordError }); return; } var loginUserRequest = { email : email.value, password : password.value, }; loginUser(loginUserRequest).unwrap().then((payload) => { setDataInAsyncStorage('logged_in_user', JSON.stringify(payload)); dispatch(authSlice.actions.setAuthToken(payload.auth_token)); }).catch((error) => { console.log(error); setError(getErrorMessageFromErrorListDTOResponse(error)); setVisible(true)}); // navigation.navigate('Dashboard'); }; return (<Background><Logo /><Header>Sign In</Header><View><StyledTextInput label="Email" returnKeyType="next" value={email.value} onChangeText={text => setEmail({ value: text, error: '' })} error={!!email.error} errorText={email.error} autoCapitalize="none" autoCompleteType="email" textContentType="emailAddress" keyboardType="email-address"></StyledTextInput></View><View><StyledTextInput label="Password" returnKeyType="done" value={password.value} onChangeText={text => setPassword({ value: text, error: '' })} error={!!password.error} errorText={password.error} secureTextEntry></StyledTextInput><Snackbar visible={visible} onDismiss={onDismissSnackBar}> {error}</Snackbar></View><View style={styles.forgotPassword}><TouchableOpacity onPress={() => { navigation.navigate("ForgotPassword") }}><Text style={styles.forgotPasswordLabel}>Forgot your password?</Text></TouchableOpacity></View><StyledButton mode="outlined" onPress={_onLoginPressed} color = "#BAC8EF"> Login</StyledButton></Background> )}export default LoginScreen
I am relatively very new to using redux, react native, rtk query and central state management.The problem I am facing is all the states are updating properly, but the app is not rerendering to display the proper current state that is the auth token despite getting updated is not redirecting to a new drawer screen navigator conditionally. It however does no action but works fine when refreshed