首页 文章

成功执行异步redux操作后转换到另一个路由

提问于
浏览
56

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

  • container 挂钩到redux并处理动作,存储订阅等

  • list 显示我的项目列表

  • new 这是一个向列表中添加新项目的表单

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

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

这样既可以显示 list 也可以显示 form ,但不能同时显示两者 .

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

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

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

这是正确的方法吗?或者我应该以某种方式触发另一个动作来触发路线改变?

5 回答

  • 28

    如果您不想使用更完整的解决方案,如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兼容 .

  • 18

    对于那些使用中间件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;
    }
    
  • 0

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

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

    因此,您需要确保 successful 操作具有 redirect 属性 . 另请注意,此中间件不会触发 next() . 这是有目的的,因为路径转换应该是动作链的结束 .

  • 0

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

    这是我使用的步骤:

    • 通过在react-router <Route/> 组件中渲染组件或使用 withRouter 创建高阶组件,将react-react history prop传递给组件 .

    • 接下来,创建要重定向到的路径(我称之为 to ) .

    • 第三,用 historyto 调用你的redux动作 .

    • 最后,当您想要重定向时(例如,当您的redux操作结算时),请调用 history.push(to) .

  • 25

    我知道我在派对上已经很晚了,因为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',data:WHATEVER_YOU_WANTED_TO_PASS)

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

相关问题