Transition to another route on successful async re

2019-01-30 06:23发布

问题:

I have a pretty simple set of react components:

  • container that hooks into redux and handles the actions, store subscriptions, etc
  • list which displays a list of my items
  • new which is a form to add a new item to the list

I have some react-router routes as follows:

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

so that either the list or the form are shown but not both.

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:

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?

回答1:

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

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 suggested but a tiny bit more sophisticated. It still uses the same history library under the hood so it's compatible with React Router.



回答2:

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 successful actions have a redirect property. Also note, this middleware does not trigger next(). This is on purpose as a route transition should be the end of the action chain.



回答3:

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 dispatch Promise inside of your actions, like so:

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.

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


回答4:

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-

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

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

you just need to import your api from the module.

share|improve this answer
0

If you're using react-redux and react-router, then I think this link provides a great solution.

Here's the steps I used:

  • Pass in a react-router history prop 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 history and to.
  • Finally, when you want to redirect (e.g., when your redux action resolves), call history.push(to).
share|improve this answer

Your Answer

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged javascript reactjs react-router redux or ask your own question.

收藏的人(0)

Ta的文章 更多文章
登录 后发表评论
0条评论
还没有人评论过~