Was ist mapDispatchToProps?


358

Ich habe die Dokumentation für die Redux-Bibliothek gelesen und sie enthält das folgende Beispiel:

Zusätzlich zum Lesen des Status können Containerkomponenten Aktionen auslösen. Auf ähnliche Weise können Sie eine aufgerufene Funktion definieren mapDispatchToProps(), die die dispatch()Methode empfängt und Rückruf-Requisiten zurückgibt, die Sie in die Präsentationskomponente einfügen möchten.

Das macht eigentlich keinen Sinn. Warum brauchen Sie, mapDispatchToPropswenn Sie bereits haben mapStateToProps?

Sie bieten auch dieses praktische Codebeispiel:

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

Kann jemand bitte in Laienbegriffen erklären, was diese Funktion ist und warum sie nützlich ist?

Antworten:


577

Ich habe das Gefühl, dass keine der Antworten herauskristallisiert hat, warum dies mapDispatchToPropsnützlich ist.

Dies kann wirklich nur im Kontext des container-componentMusters beantwortet werden , das ich am besten verstanden habe, indem ich zuerst gelesen habe: Containerkomponenten, dann Verwendung mit Reagieren .

Kurz gesagt, Sie componentssollten sich nur mit dem Anzeigen von Dingen befassen. Der einzige Ort, an dem sie Informationen erhalten sollen, sind ihre Requisiten .

Getrennt von "Anzeigen von Sachen" (Komponenten) ist:

  • wie du das Zeug zum Anzeigen bringst,
  • und wie Sie mit Ereignissen umgehen.

Dafür containerssind da.

Daher componentsieht ein "gut gestaltetes" Muster so aus:

class FancyAlerter extends Component {
    sendAlert = () => {
        this.props.sendTheAlert()
    }

    render() {
        <div>
          <h1>Today's Fancy Alert is {this.props.fancyInfo}</h1>
          <Button onClick={sendAlert}/>
        </div>
     }
}

Sehen Sie, wie diese Komponente die Informationen erhält, die sie von Requisiten anzeigt (die über aus dem Redux-Store kamen mapStateToProps), und wie sie ihre Aktionsfunktion von ihren Requisiten erhält : sendTheAlert().

Hier mapDispatchToPropskommt es ins Spiel: im entsprechendencontainer

// FancyButtonContainer.js

function mapDispatchToProps(dispatch) {
    return({
        sendTheAlert: () => {dispatch(ALERT_ACTION)}
    })
}

function mapStateToProps(state) {
    return({fancyInfo: "Fancy this:" + state.currentFunnyString})
}

export const FancyButtonContainer = connect(
    mapStateToProps, mapDispatchToProps)(
    FancyAlerter
)

Ich frage mich, ob Sie sehen können, jetzt, wo es die container 1 ist , die über Redux und Versand und Lagerung und Zustand und ... Zeug Bescheid weiß.

Das componentin dem Muster, FancyAlerterdas das Rendern ausführt, muss nichts davon wissen: Es erhält seine Methode onClick, um über seine Requisiten auf die Schaltfläche zuzugreifen.

Und ... mapDispatchToPropswar das nützliche Mittel, das Redux bietet, damit der Container diese Funktion problemlos an die verpackte Komponente seiner Requisiten weitergeben kann.

All dies sieht dem ToDo-Beispiel in den Dokumenten und einer weiteren Antwort hier sehr ähnlich, aber ich habe versucht, es im Lichte des Musters zu werfen, um zu betonen, warum .

(Hinweis: Sie können nicht mapStateToPropsfür den gleichen Zweck wie mapDispatchToPropsdie wesentlichen Grund dafür , dass Sie keinen Zugriff auf dispatchinnen , mapStateToPropdamit Sie nicht benutzen können. mapStateToPropsDer umwickelten Komponente zu geben , ein Verfahren , dass Verwendungen dispatch.

Ich weiß nicht, warum sie es in zwei Mapping-Funktionen unterteilt haben - es wäre vielleicht ordentlicher gewesen, wenn mapToProps(state, dispatch, props) IE eine Funktion für beide Funktionen hätte!


1 Beachten Sie, dass ich den Container absichtlich explizit benannt habe FancyButtonContainer, um hervorzuheben, dass es sich um ein "Ding" handelt - die Identität (und damit die Existenz!) Des Containers als "Ding" geht manchmal in der Kurzform verloren

export default connect(...) ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Syntax, die in den meisten Beispielen gezeigt wird


5
Ich würde immer noch gerne wissen: Was ist mit der erforderlichen Funktionalität, die nicht durch direkten Aufruf von store.dispatch aus einer Komponente heraus gehandhabt werden kann?
Pixelpax

8
@ user2130130 Keine. Es geht um gutes Design. Wenn Sie Ihre Komponente mit store.dispatch gekoppelt haben, dann stecken Sie mit a fest, wenn Sie sich entscheiden, Redux herauszufiltern oder es an einem Ort zu verwenden, der nicht auf Redxu basiert (oder an etwas anderem, an das ich jetzt nicht denken kann) viele Änderungen. Ihre Frage lautet: "Warum beschäftigen wir uns mit" guten Entwurfspraktiken "? Sie erhalten dieselbe Funktionalität, wie auch immer Sie sie codieren." Mit mapDispatchToProps können Sie gut gestaltete, sauber entkoppelte Komponenten schreiben.
GreenAsJade

4
Was ich hier wirklich nicht verstehe, ist: ALERT_ACTIONIst das die Aktionsfunktion oder die type, die von der Aktionsfunktion zurückgegeben wird? : / so verblüfft
Jamie Hutber

1
@JamieHutber Streng genommen hat ALERT_ACTION nichts mit dieser Frage zu tun. Es ist ein gültiges Argument für den Versand, und in meinem Code stammt es von einem "Action Builder", der ein Objekt zurückgibt, das der Versand verwendet, wie in redux.js.org/docs/api/Store.html#dispatch beschrieben . Der Hauptpunkt hierbei ist, dass das Aufrufen des Versands im Container beschrieben und an die Komponenten-Requisiten übergeben wird. Die Komponente erhält nur Funktionen von ihren Requisiten, nirgendwo anders. Die "falsche" Vorgehensweise in diesem Muster besteht darin, den Versand an die Komponente zu übergeben und denselben Aufruf in der Komponente durchzuführen.
GreenAsJade

1
Wenn Sie mehrere Aktionsersteller haben, die als Requisiten an die untergeordnete Komponente übergeben werden müssen, besteht eine Alternative darin, sie mit bindActionCreators in mapDispatchToProps zu verpacken (siehe redux.js.org/docs/api/bindActionCreators.html ). Eine andere Alternative besteht darin, einfach ein Objekt von Aktionserstellern zum Verbinden () bereitzustellen, z. B. zum Verbinden (mapStateToProps, {actioncreators}). React-Redux verpackt sie mit dispatch () für Sie.
Dave

81

Es ist im Grunde eine Abkürzung. Also anstatt schreiben zu müssen:

this.props.dispatch(toggleTodo(id));

Sie würden mapDispatchToProps wie in Ihrem Beispielcode gezeigt verwenden und dann an anderer Stelle schreiben:

this.props.onTodoClick(id);

oder wahrscheinlicher in diesem Fall hätten Sie das als Ereignishandler:

<MyComponent onClick={this.props.onTodoClick} />

Hier gibt es ein hilfreiches Video von Dan Abramov: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist


Vielen Dank. Ich frage mich auch, wie der Versand überhaupt zu den Requisiten hinzugefügt wird.
Code Whisperer

14
Wenn Sie keine eigene mapDispatchFunktion bereitstellen , verwendet Redux eine Standardeinstellung. Diese Standardfunktion mapDispatchnimmt einfach die dispatchFunktionsreferenz und gibt sie Ihnen als this.props.dispatch.
Markerikson

7
Die Versandmethode wird von der Provider Component
Diego Haz

55

mapStateToProps()ist ein Dienstprogramm, mit dem Ihre Komponente den aktualisierten Status erhält (der von einigen anderen Komponenten aktualisiert wird). Es
mapDispatchToProps()ist ein Dienstprogramm, mit dem Ihre Komponente ein Aktionsereignis auslösen kann (Auslösen einer Aktion, die zu einer Änderung des Anwendungsstatus führen kann).


23

mapStateToProps, mapDispatchToPropsUnd connectvon react-reduxBibliothek bietet eine bequeme Möglichkeit für den Zugriff auf Ihre stateund dispatchFunktion Ihres Shops. Im Grunde genommen ist connect eine Komponente höherer Ordnung. Sie können auch als Wrapper denken, wenn dies für Sie sinnvoll ist. Jedes Mal, wenn Ihre stateÄnderung geändert mapStateToPropswird, wird sie mit Ihrer neuen aufgerufen. stateAnschließend wird beim propsAktualisieren der Komponente die Renderfunktion ausgeführt, um Ihre Komponente im Browser zu rendern. mapDispatchToPropsspeichert auch Schlüsselwerte auf der propsIhrer Komponente, normalerweise haben sie die Form einer Funktion. Auf diese Weise können Sie stateÄnderungen an Ihrer Komponente auslösen onClick.onChange Ereignissen .

Aus Dokumenten:

const TodoListComponent = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

const TodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList) 

Stellen Sie außerdem sicher, dass Sie mit den Funktionen Statuslos reagieren und Komponenten höherer Ordnung vertraut sind


Der Versand ist also im Grunde genommen wie ein Ereignis?
Code Whisperer

2
Es könnte zu Fall zusammenhängen, Versand ist nur eine Funktion und der einzige Weg , um Ihre Anwendung zu ändern Zustand . Mit mapStateToProps können Sie die Versandfunktion Ihres Geschäfts für React Component verfügbar machen . Beachten Sie auch, dass connect kein Teil von Redux ist. Es handelt sich lediglich um ein Dienstprogramm und eine Boilerplate-Reduktionsbibliothek namens React-Redux , um mit React und Redux zu arbeiten. Sie können das gleiche Ergebnis ohne React-Redux erzielen, wenn Sie Ihren Shop von der Root-React-Komponente an untergeordnete Elemente übergeben .
Vlad Filimon

3

mapStateToPropsempfängt das stateund propsund ermöglicht es Ihnen, Requisiten aus dem Status zu extrahieren, um sie an die Komponente zu übergeben.

mapDispatchToPropsempfängt dispatchund propsund ist dazu gedacht, dass Sie Aktionsersteller an den Versand binden. Wenn Sie also die resultierende Funktion ausführen, wird die Aktion gesendet.

Ich finde, dies erspart Ihnen nur die Notwendigkeit, dispatch(actionCreator())innerhalb Ihrer Komponente zu arbeiten, wodurch es ein bisschen einfacher zu lesen ist.

https://github.com/reactjs/react-redux/blob/master/docs/api.md#arguments


Vielen Dank, aber was ist der Wert der dispatchMethode? Woher kommt das?
Code Whisperer

Oh. Durch das Versenden startet die Aktion im Grunde genommen den unidirektionalen Redux / Flux-Fluss. Die anderen Antworten scheinen Ihre Frage besser beantwortet zu haben.
Harry Moreno

Die Versandmethode basiert auch auf der von sich <Provider/>selbst bereitgestellten Verbesserung . Es macht seine eigene Magie von Komponenten höherer Ordnung, um sicherzustellen, dass der Versand in seinen untergeordneten Komponenten verfügbar ist.
Ricardo Magalhães

3

Angenommen, es gibt eine Aktion für Redux als:

export function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

Wenn Sie es importieren,

import {addTodo} from './actions';

class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.onTodoClick(); // This prop acts as key to callback prop for mapDispatchToProps
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

const mapDispatchToProps = dispatch => {
    return {
      onTodoClick: () => { // handles onTodoClick prop's call here
        dispatch(addTodo())
      }
    }
}

export default connect(
    null,
    mapDispatchToProps
)(Greeting);

Wie der Funktionsname sagt mapDispatchToProps(), Kartedispatch Aktion den Requisiten zu (den Requisiten unserer Komponente).

Prop onTodoClickist also ein mapDispatchToPropsFunktionsschlüssel, der die Weiterleitung von Versandaktionen delegiert addTodo.

Auch wenn Sie den Code kürzen und die manuelle Implementierung umgehen möchten, können Sie dies tun:

import {addTodo} from './actions';
class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.addTodo();
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

export default connect(
    null,
    {addTodo}
)(Greeting);

Was genau bedeutet

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.