J'ai un ensemble assez simple de composants de réaction:
container
qui se raccorde à redux et gère les actions, les abonnements aux magasins, etc.list
qui affiche une liste de mes articlesnew
qui est un formulaire pour ajouter un nouvel élément à la listeJ'ai quelques react-router routes comme suit:
<Route name='products' path='products' handler={ProductsContainer}>
<Route name='productNew' path='new' handler={ProductNew} />
<DefaultRoute handler={ProductsList} />
</Route>
de sorte que soit la list
soit la form
sont montrés mais pas les deux.
Ce que j'aimerais faire, c'est que l'application revienne à la liste une fois qu'un nouvel élément a été ajouté avec succès.
Ma solution jusqu'ici consiste à avoir une .then()
après la async dispatch
:
dispatch(actions.addProduct(product)
.then(this.transitionTo('products'))
)
Est-ce la bonne façon de faire ou devrais-je déclencher une autre action pour déclencher le changement d'itinéraire?
Si vous ne souhaitez pas utiliser une solution plus complète telle que Redux Router , vous pouvez utiliser Transitions de l'historique Redux qui vous permet d'écrire du code comme celui-ci:
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'
}
})
}
};
}
Ceci est similaire à ce que vous avez suggéré mais un peu plus sophistiqué. Il utilise toujours la même bibliothèque historique sous le capot, ce qui le rend compatible avec React Router.
J'ai fini par créer un middleware super simple qui ressemble à ça:
import history from "../routes/history";
export default store => next => action => {
if ( ! action.redirect ) return next(action);
history.replaceState(null, action.redirect);
}
Donc, à partir de là, vous devez simplement vous assurer que vos actions successful
ont une propriété redirect
. Notez également que ce middleware ne déclenche pas next()
. C'est intentionnel, car une transition d'itinéraire devrait être la fin de la chaîne d'action.
Pour ceux qui utilisent une couche d'API middleware pour résumer leur utilisation de quelque chose comme isomorphic-fetch , et qui utilisent également redux-thunk , vous pouvez simplement chaîner votre promesse dispatch
dans vos actions , ainsi:
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));
}
});
};
}
Cela réduit le besoin d'ajouter des bibliothèques dans votre code comme suggéré ici , et co-localise également vos actions avec leurs redirections comme dans redux-history-transitions .
Voici à quoi ressemble mon magasin:
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;
}
Je sais que je suis un peu en retard dans la soirée, car la navigation de réaction est déjà incluse dans la documentation de réaction-native, mais elle peut néanmoins être utile pour les utilisateurs qui ont utilisé/utilisé Navigator api dans leurs applications. petit hack, je sauve une instance de navigateur dans un objet dès que renderScene se produit-
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}/>
}
mon fichier api est quelque chose comme ça
'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;
maintenant, dans vos actions, vous pouvez simplement appeler
api.navigator.Push ({Nom: 'nom de route', données: WHATEVER_YOU_WANTED_TO_PASS)
il vous suffit d'importer votre API depuis le module.
Si vous utilisez react-redux et react-router , alors je pense ce lien fournit une excellente solution.
Voici les étapes que j'ai suivies:
history
à votre composant, soit en le rendant dans un composant rea-router <Route/>
, soit en créant un composant d'ordre supérieur à l'aide de withRouter
.to
).history
et to
.history.Push(to)
.