it-swarm.com.ru

Переход на другой маршрут при успешном асинхронном редукционном действии

У меня есть довольно простой набор реагирующих компонентов:

  • container, который подключается к redux и обрабатывает действия, сохраняет подписки и т. д.
  • list который отображает список моих товаров
  • new - форма для добавления нового элемента в список

У меня есть некоторые реакции-маршрутизатор маршруты следующим образом:

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

так что либо list, либо form отображаются, но не оба.

Я хотел бы, чтобы приложение перенаправляло обратно в список после успешного добавления нового элемента.

Мое решение до сих пор состоит в том, чтобы иметь .then() после асинхронного dispatch:

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

Это правильный способ сделать это, или я должен запустить другое действие, чтобы вызвать изменение маршрута?

56
Clarkie

Если вы не хотите использовать более полное решение, такое как 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.

28
Dan Abramov

В итоге я создал супер простое промежуточное программное обеспечение, которое выглядит примерно так:

import history from "../routes/history";

export default store => next => action => {

    if ( ! action.redirect ) return next(action);

    history.replaceState(null, action.redirect);
}

Поэтому вам просто нужно убедиться, что ваши действия successful имеют свойство redirect. Также обратите внимание, что это промежуточное ПО не вызывает next(). Это сделано специально, так как переход по маршруту должен быть концом цепочки действий.

25
silkAdmin

Для тех, кто использует уровень 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;
}
18
Cameron

Я знаю, что немного опоздал на вечеринку, так как реагирующая навигация уже включена в документацию о реагировании, но все же она может быть полезна для пользователей, которые использовали/используют API-интерфейс Navigator в своих приложениях ... немного хак, я сохраняю экземпляр навигатора в объекте, как только происходит 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 ({Имя: «имя-маршрута», данные: WHATEVER_YOU_WANTED_TO_PASS)

вам просто нужно импортировать ваш API из модуля.

0
Manjeet Singh

Если вы используете response-redux и Reaction-router , то я думаю, что эта ссылка обеспечивает отличное решение.

Вот шаги, которые я использовал:

  • Передайте history prop реагирующего маршрутизатора вашему компоненту либо путем рендеринга вашего компонента в компоненте <Route/> маршрутизатора реакции, либо путем создания компонента более высокого порядка с использованием withRouter.
  • Затем создайте маршрут, на который вы хотите перенаправить (я назвал мой to).
  • В-третьих, вызовите свое избыточное действие с помощью history и to.
  • Наконец, когда вы хотите перенаправить (например, когда ваше действие переизбытка разрешается), вызовите history.Push(to).
0
Brad W