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 itself
export 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>
);
}
}
应用程序.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>
);
}
登录屏幕.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
我对使用 redux、react native、rtk 查询和中央状态管理比较陌生。我面临的问题是所有状态都在正确更新,但是应用程序没有重新渲染以显示正确的当前状态,即身份验证令牌,尽管更新没有有条件地重定向到新的抽屉屏幕导航器。然而,它没有任何动作,但在刷新时可以正常工作