Redux: mapStateToProps () wird nicht aufgerufen

Erstellt am 13. Mai 2016  ·  4Kommentare  ·  Quelle: reduxjs/redux

Ich habe unzählige Dokumentationen gelesen - auf allen beliebten Websites - aber nirgends habe ich eine Antwort gefunden. Ich frage hier, ob ich eine Dokumentation oder ein wichtiges Verständnis verpasst habe.

Das Problem, das ich sehe, ist, dass die mapStateToProps () -Funktion meiner Komponente nur einmal (bei der Initialisierung) aufgerufen wird. Es wird nie wieder aufgerufen, auch wenn der Reduzierer aufgerufen wird. Ich fange an zu denken, dass es daran liegt, dass ich nicht verstehe, wie Aktionen / Reduzierer / Requisiten miteinander verbunden sind.

Lassen Sie mich zuerst sagen, was ich weiß:

  • Ich verstehe, dass Aktionen Aktualisierungen eines Teils (einer Eigenschaft) dieses Speichers beschreiben.
  • Ich verstehe, dass jeder Reduzierer für die Aktualisierung seines Slice / Teils des Geschäfts verantwortlich ist. (Und ich verstehe definitiv, dass der Reduzierer ein neues Objekt für seine Scheibe zurückgeben muss.)
  • Ich verstehe, dass mapStateToProps bestimmte Daten aus dem Speicher "aufnimmt" und sie als Requisiten an die genannte Komponente weitergibt.

Aber ... Ich habe keine Beschreibung gefunden, wie Aktionen, Reduzierungen und mapStateToProps miteinander zusammenhängen. Meine Fragen:

  • Ich stelle mir den Speicher als Objekt vor, mit Eigenschaften, die Daten über den Status der Anwendung enthalten. Diese Eigenschaften der obersten Ebene können Objekte sein, die einen Unterbaum zum Speichern von Informationen zu einem Teil der Anwendung bereitstellen. Ist das wahr?
  • Welche Eigenschaft (oder Unterbaum des Geschäfts) wird aktualisiert, wenn eine Aktion an das Geschäft gesendet wird? Es scheint, dass eine Eigenschaft innerhalb des Geschäfts automatisch erstellt / zugeordnet wird, aber wie wird dies bestimmt?
  • Woher "weiß" mapStateToProps, dass es auf Aktualisierungen der richtigen Eigenschaft / des richtigen Teils des Geschäfts wartet? Was verbindet sie?
  • Wie könnte ich das debuggen? Was muss ich tun, um herauszufinden, warum das Versenden der Aktion mapStateToProps nicht auslöst?
  • Oder denke ich falsch darüber nach ...?
question

Hilfreichster Kommentar

Haben Sie http://redux.js.org/docs/Troubleshooting.html durchgesehen und überprüft, ob Ihr Fall nicht zu den darin beschriebenen Problemen gehört?

Ich stelle mir den Speicher als Objekt vor, mit Eigenschaften, die Daten über den Status der Anwendung enthalten. Diese Eigenschaften der obersten Ebene können Objekte sein, die einen Unterbaum zum Speichern von Informationen zu einem Teil der Anwendung bereitstellen. Ist das wahr?

Ja. Store enthält das Statusobjekt der obersten Ebene intern. Es bietet Zugriff auf dieses Objekt von store.getState() . Dieses Objekt entspricht dem, was Sie vom Root-Reduzierer zurückgeben, und es ist oft baumartig.

Welche Eigenschaft (oder Unterbaum des Geschäfts) wird aktualisiert, wenn eine Aktion an das Geschäft gesendet wird? Es scheint, dass eine Eigenschaft innerhalb des Geschäfts automatisch erstellt / zugeordnet wird, aber wie wird dies bestimmt?

Nein, es wird nichts automatisch erstellt. Der Store zeigt gerade auf das Ergebnis des Aufrufs Ihres Root-Reduzierers.

Wenn Ihr Root-Reducer eine Funktion ist, die Sie selbst geschrieben haben, erhalten Sie das Ergebnis, nachdem Sie eine Aktion ausgelöst haben:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

Wenn Sie den Root-Reducer mit so etwas wie combineReducers({ foo, bar }) generieren, ist es dasselbe, als hätten Sie einen Root-Reducer von Hand geschrieben, der so aussieht:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

Hierher kommen oft die Eigenschaften des Staates. Ihre Werte werden durch die Rückgabe Ihrer foo und bar -Reduzierer während der Ausführung der Aktion bestimmt, sodass Sie wieder die volle Kontrolle über sie haben.

Woher "weiß" mapStateToProps, dass es auf Aktualisierungen der richtigen Eigenschaft / des richtigen Teils des Geschäfts wartet? Was verbindet sie?

Sie übergeben die Funktion mapStateToProps an connect() . Es wird eine Komponente generiert, die store.subscribe() , um jede Änderung am Geschäft abzuhören. Wenn sich das Geschäft geändert hat, liest die generierte Komponente store.getState() und übergibt sie an mapStateToProps() , um die nächsten weitergegebenen Requisiten zu bestimmen. Wenn sie sich geändert haben, wird Ihre Komponente mit ihnen neu gerendert.

Wie könnte ich das debuggen? Was muss ich tun, um herauszufinden, warum das Versenden der Aktion mapStateToProps nicht auslöst?

Fügen Sie eine Middleware wie https://github.com/theaqua/redux-logger hinzu. Stellen Sie sicher, dass der Status nach der Aktion wie erwartet aktualisiert wird. Wenn mapStateToProps nicht einmal angerufen wird, bedeutet das, dass

  • Entweder haben Sie vergessen, dispatch() eine Aktion auszuführen und haben gerade einen Aktionsersteller angerufen.
  • Oder Ihr Reduzierer hat einen referenziell identischen Wert zurückgegeben, sodass connect() sich nicht die Mühe gemacht hat, mapStateToProps() .

Beide Fälle sind unter http://redux.js.org/docs/Troubleshoot.html beschrieben.

In Zukunft bitten wir Sie, zuerst Fragen zu StackOverflow zu stellen und den Issue-Tracker zu verwenden, wenn Sie sicher sind, dass die Bibliothek einen Fehler enthält, den Sie anhand eines Beispiels, das Sie freigeben können, konsistent reproduzieren können.

Vielen Dank!

Alle 4 Kommentare

Haben Sie http://redux.js.org/docs/Troubleshooting.html durchgesehen und überprüft, ob Ihr Fall nicht zu den darin beschriebenen Problemen gehört?

Ich stelle mir den Speicher als Objekt vor, mit Eigenschaften, die Daten über den Status der Anwendung enthalten. Diese Eigenschaften der obersten Ebene können Objekte sein, die einen Unterbaum zum Speichern von Informationen zu einem Teil der Anwendung bereitstellen. Ist das wahr?

Ja. Store enthält das Statusobjekt der obersten Ebene intern. Es bietet Zugriff auf dieses Objekt von store.getState() . Dieses Objekt entspricht dem, was Sie vom Root-Reduzierer zurückgeben, und es ist oft baumartig.

Welche Eigenschaft (oder Unterbaum des Geschäfts) wird aktualisiert, wenn eine Aktion an das Geschäft gesendet wird? Es scheint, dass eine Eigenschaft innerhalb des Geschäfts automatisch erstellt / zugeordnet wird, aber wie wird dies bestimmt?

Nein, es wird nichts automatisch erstellt. Der Store zeigt gerade auf das Ergebnis des Aufrufs Ihres Root-Reduzierers.

Wenn Ihr Root-Reducer eine Funktion ist, die Sie selbst geschrieben haben, erhalten Sie das Ergebnis, nachdem Sie eine Aktion ausgelöst haben:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

Wenn Sie den Root-Reducer mit so etwas wie combineReducers({ foo, bar }) generieren, ist es dasselbe, als hätten Sie einen Root-Reducer von Hand geschrieben, der so aussieht:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

Hierher kommen oft die Eigenschaften des Staates. Ihre Werte werden durch die Rückgabe Ihrer foo und bar -Reduzierer während der Ausführung der Aktion bestimmt, sodass Sie wieder die volle Kontrolle über sie haben.

Woher "weiß" mapStateToProps, dass es auf Aktualisierungen der richtigen Eigenschaft / des richtigen Teils des Geschäfts wartet? Was verbindet sie?

Sie übergeben die Funktion mapStateToProps an connect() . Es wird eine Komponente generiert, die store.subscribe() , um jede Änderung am Geschäft abzuhören. Wenn sich das Geschäft geändert hat, liest die generierte Komponente store.getState() und übergibt sie an mapStateToProps() , um die nächsten weitergegebenen Requisiten zu bestimmen. Wenn sie sich geändert haben, wird Ihre Komponente mit ihnen neu gerendert.

Wie könnte ich das debuggen? Was muss ich tun, um herauszufinden, warum das Versenden der Aktion mapStateToProps nicht auslöst?

Fügen Sie eine Middleware wie https://github.com/theaqua/redux-logger hinzu. Stellen Sie sicher, dass der Status nach der Aktion wie erwartet aktualisiert wird. Wenn mapStateToProps nicht einmal angerufen wird, bedeutet das, dass

  • Entweder haben Sie vergessen, dispatch() eine Aktion auszuführen und haben gerade einen Aktionsersteller angerufen.
  • Oder Ihr Reduzierer hat einen referenziell identischen Wert zurückgegeben, sodass connect() sich nicht die Mühe gemacht hat, mapStateToProps() .

Beide Fälle sind unter http://redux.js.org/docs/Troubleshoot.html beschrieben.

In Zukunft bitten wir Sie, zuerst Fragen zu StackOverflow zu stellen und den Issue-Tracker zu verwenden, wenn Sie sicher sind, dass die Bibliothek einen Fehler enthält, den Sie anhand eines Beispiels, das Sie freigeben können, konsistent reproduzieren können.

Vielen Dank!

Antwort in der richtigen Reihenfolge:

  • Redux geht im Allgemeinen davon aus, dass das oberste Element Ihres Statusbaums ein einfaches Javascript-Objekt ist (obwohl es auch üblich ist, die von der Immutable.js-Bibliothek bereitgestellten Datentypen zu verwenden). Was Sie in dieses Objekt einfügen und wie Sie den Inhalt strukturieren, liegt ganz bei Ihnen. Der gebräuchlichste Ansatz besteht darin, die Dinge nach Domänen zu organisieren. Ein Statusbaum für eine hypothetische Blog-App könnte beispielsweise folgendermaßen aussehen: { users : {}, posts : {}, comments : {}, ui : {} } . Siehe http://redux.js.org/docs/FAQ.html#reducers -share-state und http://redux.js.org/docs/FAQ.html#organizing -state-nested-data.
  • Technisch gesehen definieren Sie beim Erstellen Ihres Geschäfts eine einzelne "Reduzierer" -Funktion. Diese Funktion wird mit dem aktuellen Status und der eingehenden Aktion aufgerufen und ist für die Rückgabe eines neuen Statusobjekts mit allen entsprechenden Aktualisierungen verantwortlich, die unveränderlich durchgeführt werden (dh keine direkten direkten Änderungen - alles, was aktualisiert werden muss, sollte vorhanden sein Wenn Sie Kopien erstellen, sie ändern und stattdessen die Kopien zurückgeben und ein verschachteltes Feld aktualisieren, müssen Sie auch alle seine Vorfahren kopieren und aktualisieren. Da es jedoch eine schlechte Idee ist, jedes letzte Stück Aktualisierungslogik in eine Riesenfunktion zu integrieren, wird diese Aktualisierungslogik fast immer in kleinere wiederverwendbare Subreduziererfunktionen unterteilt. Wie Sie diese Logik strukturieren, liegt wieder bei Ihnen, aber nichts wird automatisch aktualisiert - es liegt an Ihrer Reduzierungslogik, dies zu tun. Das mit Redux gelieferte Dienstprogramm combineReducers macht es einfach, eine bestimmte Reduzierungsfunktion zu haben, die für die Verwaltung von Aktualisierungen eines bestimmten Datenabschnitts verantwortlich ist, z. B.: const combinedReducer = combineReducers({users : userReducer, posts : postReducer, comments : commentsReducer, ui : uiReducer});
  • Redux benachrichtigt einfach alle Abonnenten, wenn eine Aktion durch den Store ausgeführt wird. Die React Redux connect() -Funktion abonniert und ruft dann die mapStateToProps der Komponente http://redux.js.org/docs/FAQ.html#store -setup-subscriptions.
  • Die Hauptursache dafür, dass eine Komponente nicht aktualisiert wird, ist die direkte Zustandsmutation in Ihrem Reduzierer. Siehe http://redux.js.org/docs/FAQ.html#react -not-rerendering. Darüber hinaus gibt es eine Reihe von Addons, mit denen Sie Aktionen debuggen und protokollieren können. Ich habe einige davon unter https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md aufgelistet

Hoffentlich hilft das, die Dinge zu klären.

Darüber hinaus, wie Dan sagte: Nutzungsfragen sind im Allgemeinen besser für den Stapelüberlauf geeignet. Außerdem verfügt die Reactiflux-Community auf Discord über eine Reihe von Chat-Kanälen, die sich mit reaktionsbezogenen Technologien befassen, einschließlich Redux, und es gibt immer eine Reihe von Leuten, die bereit sind, Fragen zu beantworten. Es gibt einen Einladungslink unter https://www.reactiflux.com .

@ richb-hanover Sie haben wahrscheinlich den flachen Vergleich gesehen, der von der React-Redux-Verbindung durchgeführt wird. Dies bedeutet, dass in anderen Objekten verschachtelte Objekte auch dann nicht erneut gerendert werden, wenn sie geändert werden, da nur der Stammschlüssel auf Änderungen überprüft wird.

http://redux.js.org/docs/faq/ReactRedux.html#why -isnt-my-component-re-rendering-or-my-mapstatetoprops-running

@ richb-hanover In meinem Fall hat @gaearon das Problem festgestellt:

Oder Ihr Reduzierer hat einen referenziell identischen Wert zurückgegeben, sodass connect () sich nicht die Mühe gemacht hat, mapStateToProps () aufzurufen.

Ich habe dieses Update verwendet und dies war der resultierende Code

const mapStateToProps = (state, props) => {
    return { id: props.id, currentState: state[props.id] };
}

const mapDispatchToProps = (dispatch) => {
    return {
        increment: (id) => {
            dispatch({ type: 'INCREMENT', id: id })
        }
    }
}

const DumbListItem = ({
    increment,
    id,
    currentState
}) => (
        <div>
            <li onClick={() => increment()}>{id}</li>
            <span>{currentState}</span>
        </div>
    );

export const ConnectedListItem = connect(
    mapStateToProps,
    mapDispatchToProps
)(DumbListItem);

Da ich den Parameter id an den Inkrementaufruf übergeben habe (entweder als increment(id) in der Vorlage oder über den zweiten Parameter in mapDispatchToProps ), hat der Store dies nicht getan Aktualisieren Sie das Update. Überprüfen Sie daher, ob dies möglicherweise Ihr Problem ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen