0

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

4

1 回答 1

0

你不应该做类似的事情

    let state = store.getState();
    let [authToken, setAuthToken] = useState(state.authSlice.authToken);

曾经。

这里有两件事:

  • useState用于组件本地 React 状态,与 Redux 无关。即使状态值会改变,因为 的参数useState只标记了初始状态authToken除非你调用setAuthToken.
  • 你不应该store.getState()在组件中使用。

相反,做

const authToken = useSelector(state => state.authSlice.authToken)
于 2021-09-29T08:20:13.437 回答