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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32612418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:57:03  来源:igfitidea点击:

Transition to another route on successful async redux action

javascriptreactjsreact-routerredux

提问by Clarkie

I have a pretty simple set of react components:

我有一组非常简单的反应组件:

  • containerthat hooks into reduxand handles the actions, store subscriptions, etc
  • listwhich displays a list of my items
  • newwhich is a form to add a new item to the list
  • container挂钩到redux并处理操作、存储订阅等
  • list显示我的物品列表
  • new这是一种向列表中添加新项目的表单

I have some react-routerroutes as follows:

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

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

so that either the listor the formare shown but not both.

以便显示listform显示,但不显示两者。

What I'd like to do is to have the application re-route back to the list once a new item has been successfully added.

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

My solution so far is to have a .then()after the async dispatch:

到目前为止,我的解决方案是.then()在 async 之后dispatch

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

Is this the correct way to do this or should I fire another action somehow to trigger the route change?

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

采纳答案by Dan Abramov

If you don't want to use a more complete solution like Redux Router, you can use Redux History Transitionswhich lets you write code like this:

如果您不想使用更完整的解决方案,例如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'
        }
      })
    }
  };
}

This is similar to what you suggestedbut a tiny bit more sophisticated. It still uses the same historylibrary under the hood so it's compatible with React Router.

这与您建议的类似,但更复杂一点。它仍然使用相同的历史库,因此它与 React Router 兼容。

回答by silkAdmin

I ended up creating a super simple middleware that roughtly looks like that:

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

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

export default store => next => action => {

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

    history.replaceState(null, action.redirect);
}

So from there you just need to make sure that your successfulactions have a redirectproperty. Also note, this middleware does not trigger next(). This is on purpose as a route transition should be the end of the action chain.

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

回答by Cameron

For those that are using a middleware API layer to abstract their usage of something like isomorphic-fetch, and also happen to be using redux-thunk, you can simply chain off your dispatchPromise inside of your actions, like so:

对于那些使用中间件 API 层来抽象他们对isomorphic-fetch 之类的东西的使用,并且碰巧使用redux-thunk 的人,您可以简单地将您的dispatchPromise 链接到您的操作中,如下所示:

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

This reduces the need for adding libraries into your code as suggested here, and also nicely co-locates your actions with their redirects as done in redux-history-transitions.

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

Here is what my store looks like:

这是我的商店的样子:

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

回答by Manjeet Singh

I know I am little late in the party as react-navigation is already included in the react-native documentation, but still it can be useful for the user who have used/using Navigator api in their apps. what I tried is little hackish, I am saving navigator instance in object as soon as renderScene happens-

我知道我参加聚会有点晚了,因为 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}/>

}

my api file is something lke this

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

now in your actions you can simply call

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

api.navigator.push({Name:'routeName', data:WHATEVER_YOU_WANTED_TO_PASS)

api.navigator.push({Name:'routeName', data:WHATEVER_YOU_WANTED_TO_PASS)

you just need to import your api from the module.

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

回答by Brad W

If you're using react-reduxand react-router, then I think this linkprovides a great solution.

如果您使用的是react-reduxreact-router,那么我认为此链接提供了一个很好的解决方案。

Here's the steps I used:

这是我使用的步骤:

  • Pass in a react-router historyprop to your component, either by rendering your component inside a react-router <Route/>component or by creating a Higher Order Component using withRouter.
  • Next, create the route you want to redirect to (I called mine to).
  • Third, call your redux action with both historyand to.
  • Finally, when you want to redirect (e.g., when your redux action resolves), call history.push(to).
  • 通过在 react-routerhistory组件中渲染<Route/>组件或使用withRouter.
  • 接下来,创建您要重定向到的路由(我称之为 mine to)。
  • 第三,使用history和调用您的 redux 操作to
  • 最后,当您想要重定向时(例如,当您的 redux 操作解析时),请调用history.push(to).