在成功的异步 redux 操作上转换到另一条路线

Posted

技术标签:

【中文标题】在成功的异步 redux 操作上转换到另一条路线【英文标题】:Transition to another route on successful async redux action 【发布时间】:2015-12-13 06:22:20 【问题描述】:

我有一组非常简单的 react 组件:

container 挂钩到 redux 并处理操作、商店订阅等 list 显示我的项目列表 new 是一种向列表中添加新项目的表单

我有一些react-router 路由如下:

<Route name='products' path='products' handler=ProductsContainer>
  <Route name='productNew' path='new' handler=ProductNew />
  <DefaultRoute handler=ProductsList />
</Route>

这样listform 会显示,但不会同时显示。

我想做的是在成功添加新项目后让应用程序重新路由回列表。

到目前为止,我的解决方案是在异步 dispatch 之后添加一个 .then()

dispatch(actions.addProduct(product)
  .then(this.transitionTo('products'))
)

这是执行此操作的正确方法还是我应该以某种方式触发另一个操作来触发路由更改?

【问题讨论】:

你看过github.com/acdlite/redux-react-router 吗?它将路由存储存储在 redux 中,因此您可以触发路由更改作为 redux 操作。 我已经查看了redux-react-router,这需要大量重构,因此可能需要等待。如果我同时提出解决方案,我会发布答案 @Dmitry 那么问题是一旦更新了道具(例如 isAuthenticated 标志),您从哪里触发。 componentWillReceiveProps? 【参考方案1】:

如果您不想使用像Redux Router 这样更完整的解决方案,您可以使用Redux History Transitions,它可以让您编写如下代码:

export function login() 
  return 
    type: LOGGED_IN,
    payload: 
      userId: 123
    
    meta: 
      transition: (state, action) => (
        path: `/logged-in/$action.payload.userId`,
        query: 
          some: 'queryParam'
        ,
        state: 
          some: 'state'
        
      )
    
  ;

这类似于what you suggested,但更复杂一点。它仍然使用相同的 history 库,因此它与 React Router 兼容。

【讨论】:

payload: userId: 123后面需要一个逗号【参考方案2】:

我最终创建了一个超级简单的中间件,大致如下:

import history from "../routes/history";

export default store => next => action => 

    if ( ! action.redirect ) return next(action);

    history.replaceState(null, action.redirect);

因此,您只需确保您的 successful 操作具有 redirect 属性。另请注意,此中间件不会触发next()。这是故意的,因为路由转换应该是动作链的末端。

【讨论】:

不适用于 thunk 中间件?如果你从 'LOGIN_STARTED' 移动到 'LOGIN_SUCCESSFUL' 并且不调用 next 什么都不会发生。 这是最小的工作解决方案。感谢分享。 这里的../routes/history 是什么? 这里的../router/history 是什么?这仍然有效吗?【参考方案3】:

对于那些使用中间件 API 层来抽象他们对 isomorphic-fetch 之类的使用的人,并且恰好也在使用 redux-thunk,您可以简单地将您的 dispatch Promise 链接到您的操作中,就像这样:

import  push  from 'react-router-redux';
const USER_ID = // imported from JWT;

function fetchUser(primaryKey, opts) 
    // this prepares object for the API middleware


// this can be called from your container
export function updateUser(payload, redirectUrl) 
    var opts = 
        method: 'PUT',
        headers: 
            'Content-Type': 'application/json'
        ,
        body: JSON.stringify(payload)
    ;
    return (dispatch) => 
        return dispatch(fetchUser(USER_ID, opts))
            .then((action) => 
                if (action.type === ActionTypes.USER_SUCCESS) 
                    dispatch(push(redirectUrl));
                
            );
    ;

这减少了按照 here 的建议将库添加到您的代码中的需要,并且还可以很好地将您的操作与它们的重定向放在一起,就像在 redux-history-transitions 中所做的那样。

这是我的商店的样子:

import  createStore, applyMiddleware  from 'redux';
import rootReducer from '../reducers';
import thunk from 'redux-thunk';
import api from '../middleware/api';
import  routerMiddleware  from 'react-router-redux';

export default function configureStore(initialState, browserHistory) 
    const store = createStore(
        rootReducer,
        initialState,
        applyMiddleware(thunk, api, routerMiddleware(browserHistory))
    );

    return store;

【讨论】:

真的有用吗...因为它不适合我 无法正常工作,因为 url 被重定向但我在页面中的内容没有改变。即使 url 改变了它也会显示相同的页面.. 您在使用路由器吗?哪个路由器和什么附加组件?这段代码是用 React-Router 和 React-Router-Redux 编写的 这对我有用,但您的商店中必须包含 routerMiddleware github.com/reactjs/… 对于像我这样想知道函数 push 来自哪里的人:import push from 'react-router-redux'【参考方案4】:

我知道我迟到了,因为 react-navigation 已经包含在 react-native 文档中,但对于在他们的应用程序中使用/使用 Navigator api 的用户来说,它仍然很有用。 我尝试过的有点骇人听闻,一旦 renderScene 发生,我就会将导航器实例保存在对象中-

renderScene(route, navigator) 
      const Component = Routes[route.Name]
      api.updateNavigator(navigator); //will allow us to access navigator anywhere within the app
      return <Component route=route navigator=navigator data=route.data/>


我的 api 文件是这样的

'use strict';

//this file includes all my global functions
import React, Component from 'react';
import Linking, Alert, NetInfo, Platform from 'react-native';
var api = 
    navigator,
    isandroid()
        return (Platform.OS === 'android');
    ,
    updateNavigator(_navigator)
      if(_navigator)
          this.navigator = _navigator;
    ,


module.exports = api;

现在在你的行动中你可以简单地调用

api.navigator.push(Name:'routeName', 数据:WHATEVER_YOU_WANTED_TO_PASS)

您只需要从模块中导入您的 api。

【讨论】:

【参考方案5】:

如果您使用react-redux 和react-router,那么我认为this link 提供了一个很好的解决方案。

这是我使用的步骤:

通过在 react-router &lt;Route/&gt; 组件中渲染组件或使用 withRouter 创建高阶组件,将 react-router history 属性传递给您的组件。 接下来,创建您要重定向到的路线(我叫我的to)。 第三,使用historyto 调用您的redux 操作。 最后,当您想要重定向时(例如,当您的 redux 操作解析时),请致电 history.push(to)

【讨论】:

以上是关于在成功的异步 redux 操作上转换到另一条路线的主要内容,如果未能解决你的问题,请参考以下文章

将信息从一条路线传递到另一条路线:Flask ignoring redirect requests

导航到另一条路线后,Can Angccate可以继续吗?

一旦用户访问另一条路线,如何清除 redux 状态?

在我的 laravel 4 和 angularjs 应用程序中从一条路线重定向到另一条路线

如何以角度将数据从一条路线传输到另一条路线? [复制]

路线/网络将我路由到另一条路线