【问题标题】:React navigation to navigate from redux action file反应导航以从 redux 操作文件导航
【发布时间】:2018-06-04 20:59:39
【问题描述】:

我想从我的减少操作文件中导航。 第一个屏幕是登录,所以点击登录按钮后会调用一个 redux action creator 和 reducer 生成一个新状态。所以,在操作之后我想重定向到我的仪表板。

我正在使用

react native + redux + react 导航

登录组件文件(LoginCmp.js):

import React, { Component } from 'react';
import {
  Text,
  View,
  ScrollView,
  KeyboardAvoidingView
} from 'react-native';
import { connect } from 'react-redux';
import { fieldChange, LoginAction } from '../../actions';
import { Button, Section, Input, Alert } from '../Helpers';

LoginAction(){
  const payload = {
    email: this.props.email,
    password: this.props.password
  };
  this.props.LoginAction(payload); // Action call
}


render() {
    return (
      <KeyboardAvoidingView
    style={styles.container}
    behavior="padding"
      >
      <View>
    <ScrollView contentContainerStyle={styles.contentContainer}>
      <Text style={styles.headerText}> Login </Text>
      {this.alertMessage()}
      <Section>
        <Input
          placeholder="email@gmail.com"
          onChangeText={this.onFieldChange.bind(this, { actionType: 'EMAIL_CHANGED' })}
          value={this.props.email}
        />
      </Section>
      <Section>
        <Input
          secureTextEntry
          placeholder="Password"
          onChangeText={this.onFieldChange.bind(this, { actionType: 'PASSWORD_CHANGED' })}
          value={this.props.password}
        />
      </Section>
      <Section>
        <Button
          onPress={this.LoginAction.bind(this)}
          style={styles.buttonLogin}
        >
          Submit
        </Button>
      </Section>
    </ScrollView>
      </View>
      </KeyboardAvoidingView>
    );
  }
}

const mapStateToProps = ({ auth }) => {
  console.log(auth);
  return auth;
};

export default connect(mapStateToProps, { fieldChange, LoginAction })(LoginCmp);

路由器文件(Router.js):

const RouterComponent = StackNavigator({
  login: { screen: LoginCmp },
  dashboard: { screen: DashboardCmp },
});

动作创建者文件(AuthActions.js):

import firebase from 'firebase';
import { NavigationActions } from 'react-navigation';


// Login actions
export const LoginAction = (payload) => {
  return (dispatch) => {
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => loginSuccess(dispatch, user))
      .catch((error) => {
    loginFail(dispatch, error);
    });
  };
};

// Login success function

logoutSuccess = (dispatch, user) => {
// dispatch an action
dispatch({
  type: 'LOGOUT_SUCCESS',
  payload: user
});  
### From here i want to navigate to dashboard.
};

【问题讨论】:

  • 您必须订阅 redux 状态才能登录并在 redux 操作更改状态值时更改导航。这将是一个正确的方法。

标签: react-native redux react-redux jsx react-navigation


【解决方案1】:

编辑:2018 年 8 月 9 日

在对 react-navigation 进行重大重写后,不鼓励与 Redux 集成。但是,有一些新工具可让您从任何地方控制导航。例如,请参阅提供此功能的 how to create a NavigationService

不再有效 - 不要这样做

你还没有指定你的导航状态是否保存在 Redux 中,所以如果没有,你肯定应该集成 react-navigation 和 Redux。

react-navigation documentation on how to do it 非常清晰。

之后,navigating 就变成了另一个 dispatch,只有 action 来自 react-navigation:

dispatch(NavigationActions.navigate({
  routeName: 'dashboard',
}));

【讨论】:

  • 查看文档,他们真的建议不要这样做。小心。
  • @VincentDecaux 在撰写此答案时,Redux 集成是文档的一部分。从那以后,他们改变了方法,现在确实不可取。
  • 如何在调度时将对象数组从一个屏幕传递到另一个屏幕,如何在下一个屏幕中获取它 Ex) dispatch(NavigationActions.navigate({ routeName: 'SettingsScreen', params: {id}}));
【解决方案2】:
import firebase from 'firebase';
import { NavigationActions } from 'react-navigation';


// Login actions
export const LoginAction = (payload) => {
  return (dispatch) => {
    firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
      .then(user => loginSuccess(dispatch, user))
      .catch((error) => {
    loginFail(dispatch, error);
    });
  };
};

// Login success function

logoutSuccess = (dispatch, user) => {
  // dispatch an action
  dispatch({
    type: 'LOGOUT_SUCCESS',
    payload: user
  });  
  const navigateAction = NavigationActions.navigate({
      routeName: "dashboard",
      params: {},
      action: NavigationActions.navigate({ routeName: "dashboard" })
    });
  this.props.navigation.dispatch(navigateAction); // this is where you use navigation prop
};

// 将此导航减速器添加到您的根减速器

import Root from 'your navigation root path';

const navReducer = (state, action) => {
  const newState = Root.router.getStateForAction(action, state)
  return newState || state
}

export default navReducer;

【讨论】:

    【解决方案3】:

    2018 年 v2 解决方案:

    1) 定义一个 NavigationService.js 文件

    import { NavigationActions } from 'react-navigation';
    
    let navigator;
    
     function setTopLevelNavigator(navigatorRef) {
      navigator = navigatorRef;
    }
    
    function navigate(routeName, params) {
      navigator.dispatch(
        NavigationActions.navigate({
           routeName,
           params,
         }),
      );
    }
    
    
     export default {
      navigate,
      setTopLevelNavigator,
     };
    

    2) 在App.js 内部你应该有这样的东西:(redux 提供者,商店和顶级导航器之前设置)

    import AppNavigation from 'route-to-NavigationService';
    
    <Provider store={store}>
        <TopLevelNavigator
          ref={(navigatorRef) => {
          NavigationService.setTopLevelNavigator(navigatorRef);
          }}
        />
    </Provider>
    

    3) 在你的行动中: 从 'route-to-NavigationService' 导入 NavigationService;

    function logIn(){
         //async code
         ...
         dispatch(() => {
              NavigationService.navigate('RouteNameToNav'),
         });
    }
    

    额外:如果您想重置导航堆栈(即登录应该重置导航堆栈),那么在您的调度中,您应该这样做:

      dispatch(() => {
          StackActions.reset({
            index: 0,
            actions: [NavigationService.navigate('App')],
          });
        });
    

    【讨论】:

    • 什么是“TopLevelNavigator” 它来自 App.js 中的什么地方? -1 没有指导意义..
    • @TyForHelpDude 顾名思义,它是您应用的主要导航器。通常在您的项目设置中定义。
    • 你能解释一下什么是 TopLevelNavigator 吗?我不明白你的解决方案
    【解决方案4】:

    对我有用的一种 hacky 方式是您可以将导航道具发送到您的操作

    <Button rounded block onPress={() => this.props.nav(this.props.navigation)}>
        <Text>
        nav
         </Text>
    </Button>
    

    然后在您的操作文件中:

    export function navAction(navigation) {
        return (dispatch) => {
            navigation.navigate('yourRoute')
        }
    }
    

    【讨论】:

      【解决方案5】:

      我有一个简单快捷的解决方案:

      在你必须导航到特定屏幕的情况下,你可以将导航作为参数传递给你的 redux action creator 函数

      lougout 动作示例:

      Redux 操作:

      export function handleLogout(navigation) {
          return (dispatch) => {
              dispatch(handleLoggingOut(true));
              setTimeout(() => {
                  STORAGE.removeData('@FunnyLive:token').then(() => {
                      dispatch(handleLoggingOut(false));
                      navigation.navigate({routeName: 'Auth'});
                  })
              }, 2000);
          }
      }
      

      mapDispatchToProps:

      const mapDispatchToProps = (dispatch) => ({
        logout: (navigation) => dispatch(handleLogout(navigation))
      })
      

      最后你必须像这样调用动作:

      () => this.props.logout(this.props.navigation);
      

      【讨论】:

        【解决方案6】:

        在导航 5 和 Redux 中

        例如我有组件登录

        const LoginScreen = (props) => {
                return (
                        <View style={styles.continer}>
                            <Login navigation={props.navigation}/>
                        </View>
                )
        }
        

        在组件登录中我有登录功能

        import { connect} from 'react-redux';
        import {userLogin} from './action/userAction';
        
        const login =()=>{
            const {username,password, navigation } = props;
            userLogin(username,password, navigation )
        }
        
        
        const mapStateToProps = (state) => {
           return{
               username:state.auth.username,
               password:state.auth.password,
           }
          };
        
        
        
        export default connect(mapStateToProps,{userLogin})(Login) ;
        

        在 userAction 文件中

        export const userLogin = (username, password, navigation) => {
            return dispatch => {
                // .... any code
                loginSucess(dispatch, navigation)
            }
        }
        
        const loginSucess = (dispatch, navigation) => {
            dispatch({
                type: USER_LOGIN_SUCSESS,
            })
            navigation.replace("Home")
        }
        

        【讨论】:

          【解决方案7】:

          react-navigation v6 docs 中所述。您可以从反应组件外部使用反应导航功能。

          // RootNavigation.js
          
          import { createNavigationContainerRef } from '@react-navigation/native';
          
          export const navigationRef = createNavigationContainerRef()
          
          export function navigate(name, params) {
            if (navigationRef.isReady()) {
              navigationRef.navigate(name, params);
            }
          }
          
          // add other navigation functions that you need and export them
          

          Navigate without the navigation props 来自 react-navigation v5 文档

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-18
            • 2019-05-19
            • 2020-09-01
            • 1970-01-01
            相关资源
            最近更新 更多