Переход на другой маршрут при успешном действии async redux
У меня довольно простой набор реагирующих компонентов:
-
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
, но не оба.
Что бы я хотел сделать, так это вернуть приложение повторно в список после добавления нового элемента.
Моим решением до сих пор является .then()
после async dispatch
:
dispatch(actions.addProduct(product)
.then(this.transitionTo('products'))
)
Это правильный способ сделать это или мне нужно каким-то образом запустить другое действие, чтобы вызвать изменение маршрута?
Ответы
Ответ 1
Если вы не хотите использовать более полное решение, например 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'
}
})
}
};
}
Это похоже на то, что вы предложили, но немного сложнее. Он по-прежнему использует ту же библиотеку history под капотом, чтобы она совместима с React Router.
Ответ 2
Я закончил создание супер простого промежуточного программного обеспечения, которое выглядит так:
import history from "../routes/history";
export default store => next => action => {
if ( ! action.redirect ) return next(action);
history.replaceState(null, action.redirect);
}
Итак, оттуда вам нужно убедиться, что ваши действия successful
имеют свойство redirect
. Также обратите внимание, что это промежуточное ПО не запускает next()
. Это специально, так как переход маршрута должен быть завершением цепочки действий.
Ответ 3
Для тех, кто использует слой 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));
}
});
};
}
Это уменьшает необходимость добавления библиотек в ваш код, как предлагается здесь, а также красиво совмещает ваши действия с их перенаправлением, как это сделано в 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;
}
Ответ 4
Я знаю, что я немного опаздываю на вечеринку, так как реакция-навигация уже включена в документацию, предназначенную для реагирования, но все же она может быть полезна для пользователя, который использовал/использовал 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 файл - это что-то 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;
теперь в ваших действиях вы можете просто вызвать
api.navigator.push({Name: 'routeName', данные: WHATEVER_YOU_WANTED_TO_PASS)
вам просто нужно импортировать api из модуля.