Reputation: 7550
I have a pretty simple set of react components:
container
that hooks into redux and handles the actions, store subscriptions, etclist
which displays a list of my itemsnew
which is a form to add a new item to the listI 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?
Upvotes: 63
Views: 31206
Reputation: 190
If you're using react-redux and react-router, then I think this link provides a great solution.
Here's the steps I used:
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
.to
).history
and to
.history.push(to)
.Upvotes: 0
Reputation: 4800
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.
Upvotes: 26
Reputation: 4562
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.
Upvotes: 0
Reputation: 1524
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;
}
Upvotes: 20
Reputation: 268215
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.
Upvotes: 29