web-dev-qa-db-de.com

Übergang zu einer anderen Route bei erfolgreicher asynchroner Redux-Aktion

Ich habe ein ziemlich einfaches Set an Reaktionskomponenten:

  • container das sich in redux einhakt und die Aktionen abwickelt, Subskriptionen speichert usw
  • list, die eine Liste meiner Artikel anzeigt
  • new Dies ist ein Formular, um ein neues Element zur Liste hinzuzufügen

Ich habe einige Reakt-Router Routen wie folgt:

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

so dass entweder die list oder die form angezeigt wird, jedoch nicht beide.

Ich möchte, dass die Anwendung nach dem erfolgreichen Hinzufügen eines neuen Elements zurück zur Liste geleitet wird. 

Meine bisherige Lösung besteht darin, nach der asynchronen Variable dispatch eine .then() zu haben:

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

Ist dies der richtige Weg, oder sollte ich eine andere Aktion auslösen, um die Routenänderung auszulösen?

56
Clarkie

Wenn Sie keine umfassendere Lösung wie Redux Router verwenden möchten, können Sie Redux History Transitions verwenden, mit der Sie Code wie folgt schreiben können:

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

Dies ist ähnlich zu was Sie vorgeschlagen haben aber ein bisschen raffinierter. Es verwendet immer noch die gleiche history - Bibliothek unter der Haube, sodass es mit React Router kompatibel ist.

28
Dan Abramov

Am Ende habe ich eine sehr einfache Middleware erstellt, die rücksichtsvoll so aussieht:

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

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

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

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

Von dort müssen Sie also nur sicherstellen, dass Ihre successful-Aktionen eine redirect-Eigenschaft haben. Beachten Sie auch, dass diese Middleware next() nicht auslöst. Dies ist absichtlich, da ein Routenübergang das Ende der Aktionskette sein sollte.

25
silkAdmin

Für diejenigen, die eine Middleware-API-Schicht verwenden, um ihre Verwendung von etwas wie isomorphic-fetch zu abstrahieren und auch redux-thunk verwenden, können Sie Ihre dispatch Promise einfach in Ihre Aktionen einbinden wie 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));
                }
            });
    };
}

Dies verringert die Notwendigkeit, Bibliotheken in Ihrem Code hinzuzufügen, wie vorgeschlagen - hier , und lokalisiert Ihre Aktionen auch mit ihren Weiterleitungen, wie in redux-history-transitions .

So sieht mein Shop aus:

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

Ich weiß, dass ich in der Party etwas spät dran bin, da die reaktynavigation bereits in der Dokumentation zu reaktionsnativen enthalten ist, aber sie kann dennoch für Benutzer hilfreich sein, die Navigator-API in ihren Apps verwendet haben/verwendet haben wenig hackish, ich speichere die navigator-Instanz in object, sobald renderScene vorkommt- 

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

}

meine api-datei ist etwas für mich

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

jetzt können Sie in Ihren Aktionen einfach anrufen 

api.navigator.Push ({Name: 'routeName', Daten: WHATEVER_YOU_WANTED_TO_PASS)

sie müssen nur Ihre API aus dem Modul importieren.

0
Manjeet Singh

Wenn Sie React-Redux und React-Router verwenden, dann denke ich Dieser Link bietet eine großartige Lösung.

Hier sind die Schritte, die ich verwendet habe:

  • Übergeben Sie einen React-Router history prop an Ihre Komponente, indem Sie entweder Ihre Komponente in einer React-Router-<Route/>-Komponente darstellen oder eine Komponente höherer Ordnung mit withRouter erstellen.
  • Als Nächstes erstellen Sie die Route, zu der Sie umleiten möchten (ich habe meine to genannt).
  • Drittens rufen Sie Ihre Redux-Aktion mit history und to auf.
  • Wenn Sie eine Umleitung durchführen möchten (z. B., wenn Ihre Redux-Aktion ausgeführt wird), rufen Sie history.Push(to) auf.
0
Brad W