wake-up-neo.net

Wie gehe ich am besten mit einem Abruffehler in React Redux um?

Ich habe einen Reduzierer für Kunden, einen anderen für AppToolbar und einige andere ...

Nun sagen wir, dass ich eine Abrufaktion zum Löschen des Clients erstellt habe. Wenn dies fehlschlägt, habe ich Code im Client-Reduzierer, der etwas tun sollte, aber ich möchte auch einen globalen Fehler in AppToolbar anzeigen.

Die Clients und die AppToolbar-Reduzierer teilen sich jedoch nicht den gleichen Teil des Zustands, und ich kann keine neue Aktion im Reduzierer erstellen.

Wie soll ich also einen globalen Fehler anzeigen? Vielen Dank

UPDATE 1:

Ich vergesse zu erwähnen, dass ich este devstack verwende

UPDATE 2: Ich habe Eric's Antwort als richtig eingestuft, aber ich muss sagen, dass die Lösung, die ich in este verwende, eher eine Kombination aus Eric und Dans Antwort ist ... Sie müssen nur finden Was passt dir am besten in deinen Code ...

74
Dusan Plavak

Wenn Sie das Konzept "globaler Fehler" haben möchten, können Sie einen errors-Reduzierer erstellen, der auf die Aktionen addError, removeError usw. achten kann. Dann können Sie sich unter state.errors in Ihren Redux-Statusbaum einklinken und ihn nach Bedarf anzeigen lassen.

Es gibt verschiedene Möglichkeiten, wie Sie dies angehen können, aber die allgemeine Idee ist, dass globale Fehler/Nachrichten ihren eigenen Reducer dazu bringen würden, völlig getrennt von <Clients /><AppToolbar /> zu leben. Wenn eine dieser Komponenten auf errors zugreifen muss, können Sie errors natürlich als Requisite weitergeben, wo immer dies erforderlich ist.

_/Update: Codebeispiel

Hier ein Beispiel, wie es aussehen könnte, wenn Sie die "globalen Fehler" errors an Ihre oberste Ebene <App /> übergeben und diese bedingungslos rendern (falls Fehler vorhanden sind). Verwenden Sie reag-reduxs connect , um Ihre <App />-Komponente mit einigen Daten zu verbinden.

// App.js
// Display "global errors" when they are present
function App({errors}) {
  return (
    <div>
      {errors && 
        <UserErrors errors={errors} />
      }
      <AppToolbar />
      <Clients />
    </div>
  )
}

// Hook up App to be a container (react-redux)
export default connect(
  state => ({
    errors: state.errors,
  })
)(App);

Und was den Ersteller der Aktion angeht, würde er gemäß der Antwort ( redux-thunk ) Erfolgsausfälle auslösen

export function fetchSomeResources() {
  return dispatch => {
    // Async action is starting...
    dispatch({type: FETCH_RESOURCES});

    someHttpClient.get('/resources')

      // Async action succeeded...
      .then(res => {
        dispatch({type: FETCH_RESOURCES_SUCCESS, data: res.body});
      })

      // Async action failed...
      .catch(err => {
        // Dispatch specific "some resources failed" if needed...
        dispatch({type: FETCH_RESOURCES_FAIL});

        // Dispatch the generic "global errors" action
        // This is what makes its way into state.errors
        dispatch({type: ADD_ERROR, error: err});
      });
  };
}

Während Ihr Reduzierer einfach eine Reihe von Fehlern verwalten kann, fügen Sie die entsprechenden Einträge hinzu.

function errors(state = [], action) {
  switch (action.type) {

    case ADD_ERROR:
      return state.concat([action.error]);

    case REMOVE_ERROR:
      return state.filter((error, i) => i !== action.index);

    default:
      return state;
  }
}
89
Erik Aybar

Eriks Antwort ist korrekt, aber ich möchte hinzufügen, dass Sie keine separaten Aktionen auslösen müssen, um Fehler hinzuzufügen. Ein alternativer Ansatz besteht darin, einen Reducer zu haben, der jede Aktion mit einem error-Feld behandelt. Dies ist eine Frage der persönlichen Entscheidung und Konvention.

Zum Beispiel aus Redux real-world Beispiel das hat eine Fehlerbehandlung:

// Updates error message to notify about the failed fetches.
function errorMessage(state = null, action) {
  const { type, error } = action

  if (type === ActionTypes.RESET_ERROR_MESSAGE) {
    return null
  } else if (error) {
    return error
  }

  return state
}
88
Dan Abramov

Der Ansatz, den ich derzeit für einige Fehler benutze (Überprüfung der Benutzereingaben), besteht darin, dass meine Subreduzierer eine Ausnahme auslösen, sie in meinem Rootreduzierer abfangen und an das Aktionsobjekt anhängen. Dann habe ich eine Redux-Saga, die Aktionsobjekte auf Fehler untersucht und in diesem Fall den Statusbaum mit Fehlerdaten aktualisiert.

So:

function rootReducer(state, action) {
  try {
    // sub-reducer(s)
    state = someOtherReducer(state,action);
  } catch (e) {
    action.error = e;
  }
  return state;
}

// and then in the saga, registered to take every action:
function *errorHandler(action) {
  if (action.error) {
     yield put(errorActionCreator(error));
  }
}

Und dann fügen Sie den Fehler zum Statusbaum hinzu, wie Erik beschreibt.

Ich benutze es ziemlich sparsam, aber es hindert mich daran, Logik zu duplizieren, die legitim in den Reducer gehört (damit sie sich vor einem ungültigen Zustand schützen kann).

1
Gavin

was ich mache, ist, dass ich die gesamte Fehlerbehandlung pro Effekt zentral zentraliere

/**
 * central error handling
 */
@Effect({dispatch: false})
httpErrors$: Observable<any> = this.actions$
    .ofType(
        EHitCountsActions.HitCountsError
    ).map(payload => payload)
    .switchMap(error => {
        return of(confirm(`There was an error accessing the server: ${error}`));
    });
0
meanstack

schreiben Sie benutzerdefinierte Middleware, um alle mit der API verbundenen Fehler zu behandeln. In diesem Fall wird Ihr Code sauberer.

   failure/ error actin type ACTION_ERROR

   export default  (state) => (next) => (action) => {

      if(ACTION_ERROR.contains('_ERROR')){

       // fire error action
        store.dispatch(serviceError());

       }
}
0
Khalid Azam