【问题标题】:Logout error on dispatch redux with React native navigation使用 React 本机导航调度 redux 时注销错误
【发布时间】:2021-07-06 13:20:59
【问题描述】:

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

我需要调度 Logout(删除当前用户)并导航到登录页面而不再次渲染 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(这里是调度)

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
}

【问题讨论】:

    标签: react-native redux react-navigation logout dispatch


    【解决方案1】:

    您的Home 组件期望从状态中选择一个用户对象。请注意,您应该只选择您想要的特定对象state.users.current,而不是选择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);
    

    【讨论】:

    • - 不起作用,错误:TypeError: null is not an object (evalating 'currentUser.id') 此错误位于:in Home (created by ConnectFunction)
    • 第一次只在 Home 中调用 useEffect,当我按下注销时它不会被调用(我知道是因为我在函数中放了一个 console.log())
    • 第一个错误没有意义,因为它说currentUsernull,但在我们尝试访问currentUser.id 之前,我们先做了if (!currentUser) { return null; }
    • 是的,你是对的,我忘了那个条件。现在它起作用了。谢谢:)
    【解决方案2】:

    在您的情况下,您现在可以通过更改用户变量来处理 null 状态

      <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;
    

    【讨论】:

    • state = undefined 这不是正确的 redux。
    • 是的@Linda,在某些情况下不是,这就是为什么我提到我们可以根据我们的用例将其重置为某些初始状态或应用程序状态。
    • 你需要return状态的新值。你不能这样做state =
    • 在这种情况下,我们不会改变状态,我们只是为 state(local) 变量分配一些值,并将相同的变量传递给 app reducer。所以 appReducers 会返回一个新的状态。所以没有违反redux原则(状态突变)。
    猜你喜欢
    • 1970-01-01
    • 2021-08-02
    • 2020-08-03
    • 2018-06-06
    • 2017-11-22
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 2016-08-14
    相关资源
    最近更新 更多