使用 React 本机导航在 dispatch redux 上注销错误

Logout error on dispatch redux with React native navigation

在我的 React Native 应用程序中,实际上我需要使用导航和 redux 实现一个简单的注销,但是当我从主页发送注销操作时出现错误 (按下注销按钮), 因为在 Home 中我呈现当前用户并且在那一刻不存在。

我需要调度注销(删除当前用户)并在导航到登录页面后再次渲染主页或了解如何在渲染之前实现 componentWillMount.... 如何?

我的简历代码: (登录有效,我没有输入登录码)

App.tsx

import React, {useState} from 'react';
import { NavigationContainer, StackActions } from '@react-navigation/native';
//... many imports

const store = createStore(rootReducer);

export default class App extends React.Component {
   constructor(props) {
    super(props);
    this.state = { loading: true };
   }

async componentDidMount() {
  //... some code
}

render(){
   if (this.state.loading) {
     return (
       <Root>
         <AppLoading />
       </Root>
    );
   }
   else {
     return (
       <Provider store={store}>
        <Root>
          <NavigationContainer>
            <Navigator/>
          </NavigationContainer>
        </Root>
       </Provider>          
     );
   }
  }
}

Navigator.tsx

import React from 'react'
import { createStackNavigator } from '@react-navigation/stack'
import {connect} from 'react-redux'
import Login from '../Views/Login'
import Home from '../Views/Home'

const Stack = createStackNavigator();

const Navigator= (props) =>{
   const {users} = props;
   return (
        <Stack.Navigator>
            {console.log('Navigator here, '+users.current)}
            {users.current ===null ? 
                (<>    
                    <Stack.Screen name="Login" component={Login}  options={{headerShown:false}}/>
                </>)
            :   (<>    
                    <Stack.Screen name="Home" component={Home} options={{headerShown:false}}/>
                </>)
            }
        </Stack.Navigator>
    );
 }

const mapStateToProps=(state)=>{
   const {users} = state;
   return {users};
}

export default connect(mapStateToProps)(Navigator);

Home.tsx(注销后导航?)

import React from 'react'
import {Text, Container, Content, View, Button, Icon} from 'native-base'
import Styles from './Styles/HomeStyles'
import {connect} from 'react-redux'
import {Auth} from '../Services/Auth/AuthService'

const Home =(props) => {
   const {navigation, users} = props;
   return(
    <Container >
        <Content >      
            <View style={Styles.content}>                  
                <Text>Hi {users.current.id}</Text>
                <Button onPress={()=>Logout(users.current.id)} >
                    <Icon name='exit' />
                </Button>
            </View>
        </Content>
    </Container>
   );

   async function Logout(id:string){
      console.log('Function start');
      await Auth.LogoutUser(id, props);
      navigation.navigate('Login');
   }
 }

const mapStateToProps=(state)=>{
  const {users} = state;
  return {users};
}

export default connect(mapStateToProps)(Home);

UserReducer.tsx

const Initial_State={
   current:null
}

export function UserReducer(state=Initial_State, action:any){
   switch (action.type){
    case 'ADD_USER':
        return{
            ...state,
            current: action.user
        };
    case 'DELETE_USER':
        return{
            ...state,
            current: null
        };
    default:
        return state;
   }
}

AuthService.tsx(这里是dispatch)

export const Auth={
   LoginUser,
   LogoutUser
}

async function LogoutUser(id: string, props: any){
  await props.dispatch({type : 'DELETE_USER', id});
}

async function LoginUser(AuthData:IAuthData, props: any){
  //...some code
}

在您的情况下,您现在可以通过更改

来处理 users 变量的空状态
  <Text>Hi {users.current.id}</Text>

<Text>Hi {users?.current?.id}</Text>

但在实际应用中,您应该必须重置完整的应用状态,并且必须在该应用状态上管理您的条件。

示例:

import { combineReducers } from 'redux';
import UsersReducer from './UsersReducer';

  const appReducer = combineReducers({
      users: UsersReducer,
     // other Reducers if there is any.
    });

 const rootReducer = (state, action) => {
   // When logout action is dispatched  reset the action.
   if (action.type === 'USER_LOG_OUT') {
     state = undefined; // or to initial state if {} you want any data without session 
    }
    return appReducer(state, action);
   };

export default rootReducer;

您的 Home 组件需要一个从状态 selected 的用户对象。在这一点上,你应该 select 只是你想要的特定对象,state.users.current,而不是 selecting state.users 然后查看 users.current.

除非我们有用户,否则我们不希望 Home 呈现,因此我们可以 useEffect 有条件地离开页面。这意味着我们实际上不需要 await 注销,因为只要没有用户,导航就会自动发生。动作被分派 --> redux 状态改变 --> currentUser 属性改变 --> 效果运行 --> 导航发生。

const Home = (props) => {
  const { navigation, currentUser } = props;

  function Logout(id) {
    // no async/await here
    // navigation is triggered when currentUser updates
    Auth.LogoutUser(id, props);
  }

  useEffect(() => {
    if (!currentUser) {
      navigation.navigate("Login");
    }
  }, [currentUser, navigation]);

  if (!currentUser) {
    // should only end up here momentarily while navigation is taking place
    return null;
  }
  
  return (
    <Container>
      <Content>
        <View style={Styles.content}>
          <Text>Hi {currentUser.id}</Text>
          <Button onPress={() => Logout(currentUser.id)}>
            <Icon name="exit" />
          </Button>
        </View>
      </Content>
    </Container>
  );
};

const mapStateToProps = (state) => {
  return {
    currentUser: state.users.current
  };
};

export default connect(mapStateToProps)(Home);