在异步还原操作成功时转换到另一个路由

Transition to another route on successful async redux action

本文关键字:转换 另一个 路由 成功 异步 还原 操作      更新时间:2023-09-26

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

  • container,钩子到redux和处理动作,存储订阅等
  • list显示我的项目列表
  • new,这是一个窗体添加一个新的项目到列表

我有一些反应路由器路由如下:

<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'))
)

这是正确的方法,还是我应该触发另一个动作以触发路由更改?

如果你不想使用像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'
        }
      })
    }
  };
}

这与你建议的相似,但更复杂一点。它仍然在底层使用相同的历史库,所以它与React路由器兼容。

我最终创建了一个超级简单的中间件,大致看起来像这样:

import history from "../routes/history";
export default store => next => action => {
    if ( ! action.redirect ) return next(action);
    history.replaceState(null, action.redirect);
}

所以从那里你只需要确保你的successful动作有一个redirect属性。还要注意,这个中间件不会触发next()。这是故意的,因为路由转换应该是动作链的末端。

对于那些使用中间件API层来抽象他们的使用,比如同构提取,并且碰巧使用redux-thunk,你可以简单地在你的动作中链接你的dispatch承诺,像这样:

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

这减少了在代码中添加库的需要,并且还可以很好地将您的操作与其重定向放在一起,就像在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;
}

我知道我有点晚了,因为react-navigation已经包含在react-native文档中,但它仍然可以为那些在他们的应用程序中使用/使用Navigator api的用户提供帮助。我所尝试的是小hackish,我保存导航实例在对象一旦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

如果你正在使用react-redux和react-router,那么我认为这个链接提供了一个很好的解决方案。

下面是我使用的步骤:
  • 传递一个react-router history prop给你的组件,要么在react-router <Route/>组件中渲染你的组件,要么用withRouter创建一个高阶组件。
  • 接下来,创建你想重定向到的路由(我叫我的to)。
  • 第三,用historyto调用你的redux动作。
  • 最后,当你想要重定向时(例如,当你的redux动作解析时),调用history.push(to)