反应导航以从 redux 操作文件导航

Posted

技术标签:

【中文标题】反应导航以从 redux 操作文件导航【英文标题】:React navigation to navigate from redux action file 【发布时间】: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 操作更改状态值时更改导航。这将是一个正确的方法。 【参考方案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 文档

【讨论】:

以上是关于反应导航以从 redux 操作文件导航的主要内容,如果未能解决你的问题,请参考以下文章

dispatchin action redux 后导航与 react native

反应如何在 redux-saga 中导航路由器?

每次使用反应路由器导航到redux组件时,如何阻止状态存储数据在redux组件中累积

反应导航:如何在打字稿中使用 NavigationStackScreenComponent 类型传递 redux 道具

redux 状态变化时如何导航?

(React导航wix与Redux)应用程序在启动时崩溃