Qu'est-ce que mapDispatchToProps?

358

Je lisais la documentation de la bibliothèque Redux et elle a cet exemple:

En plus de lire l'état, les composants de conteneur peuvent envoyer des actions. De la même manière, vous pouvez définir une fonction appelée mapDispatchToProps()qui reçoit la dispatch()méthode et renvoie les accessoires de rappel que vous souhaitez injecter dans le composant de présentation.

Cela n'a en fait aucun sens. Pourquoi avez-vous besoin mapDispatchToPropsalors que vous en avez déjà mapStateToProps?

Ils fournissent également cet exemple de code pratique:

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

Quelqu'un peut-il expliquer en termes simples ce qu'est cette fonction et pourquoi elle est utile?

Code Whisperer
la source

Réponses:

578

J'ai l'impression qu'aucune des réponses n'a cristallisé pourquoi mapDispatchToPropsest utile.

Cela ne peut vraiment être répondu que dans le contexte du container-componentmodèle, que j'ai trouvé le mieux compris en première lecture: Composants de conteneur puis Utilisation avec React .

En un mot, vous componentsêtes censé ne vous soucier que d'afficher des choses. Le seul endroit où ils sont censés obtenir des informations est leurs accessoires .

Séparé de "l'affichage des éléments" (composants) est:

  • comment afficher les éléments,
  • et comment vous gérez les événements.

C'est pour ça containers.

Par conséquent, un "bien conçu" componentdans le modèle ressemble à ceci:

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

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

Voyez comment ce composant obtient l'information qu'il affiche d'accessoires (qui est venu du magasin redux via mapStateToProps) et il obtient également sa fonction d'action de ses accessoires: sendTheAlert().

C'est là mapDispatchToPropsqu'intervient: dans le correspondantcontainer

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

Je me demande si vous pouvez voir, maintenant que c'est le container 1 qui connaît le redux et l'expédition et le stockage et l'état et ... des trucs.

Le componentdans le motif, FancyAlerterqui fait le rendu, n'a pas besoin de savoir quoi que ce soit: il obtient sa méthode pour appeler onClickdu bouton, via ses accessoires.

Et ... mapDispatchToPropsétait le moyen utile que redux fournit pour laisser le conteneur passer facilement cette fonction dans le composant enveloppé sur ses accessoires.

Tout cela ressemble beaucoup à l'exemple des tâches dans les documents, et une autre réponse ici, mais j'ai essayé de le lancer à la lumière du motif pour souligner pourquoi .

(Remarque: vous ne pouvez pas utiliser mapStateToPropsdans le même but que mapDispatchToPropspour la raison fondamentale pour laquelle vous n'avez pas accès à l' dispatchintérieur mapStateToProp. Vous ne pouvez donc pas utiliser mapStateToPropspour donner au composant encapsulé une méthode qui utilise dispatch.

Je ne sais pas pourquoi ils ont choisi de le diviser en deux fonctions de mappage - il aurait peut-être été plus judicieux d'avoir mapToProps(state, dispatch, props) IE une fonction pour faire les deux!


1 Notez que j'ai délibérément explicitement nommé le conteneur FancyButtonContainer, pour souligner qu'il s'agit d'une «chose» - l'identité (et donc l'existence!) Du conteneur en tant que «chose» est parfois perdue dans la sténographie

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

syntaxe indiquée dans la plupart des exemples

GreenAsJade
la source
5
J'aimerais encore savoir: qu'en est-il des fonctionnalités requises qui ne peuvent pas être gérées en appelant directement store.dispatch à partir d'un composant?
pixelpax
8
@ user2130130 Aucun. Il s'agit d'un bon design. Si vous avez couplé votre composant à store.dispatch, lorsque vous décidez de prendre en compte le redux ou que vous souhaitez l'utiliser dans un endroit qui n'est pas basé sur redxu (ou autre chose à laquelle je ne peux pas penser maintenant), vous êtes coincé avec un beaucoup de changements. Votre question se généralise à "pourquoi nous dérange-t-on avec les" bonnes pratiques de conception "- vous obtenez la même fonctionnalité quel que soit le code". mapDispatchToProps est fourni pour que vous puissiez écrire des composants bien conçus et proprement découplés.
GreenAsJade
4
Ce que je n'obtiens pas vraiment ici, c'est ce qui est: ALERT_ACTIONest-ce la fonction d'action ou celle typequi est renvoyée par la fonction d'action? : / so baffed
Jamie Hutber
1
@JamieHutber Strictement, ALERT_ACTION n'a rien à voir avec cette question. C'est un argument valide pour envoyer, et comme cela arrive, dans mon code, il provient d'un "générateur d'action", qui renvoie un objet utilisé par dispatch, comme décrit redux.js.org/docs/api/Store.html#dispatch . Le point principal ici est que la façon d'appeler la répartition est décrite dans le conteneur et transmise aux accessoires des composants. Le composant n'obtient des fonctions que de ses accessoires, nulle part ailleurs. La "mauvaise" façon de le faire dans ce modèle serait de passer la répartition au composant et de faire le même appel dans le composant.
GreenAsJade
1
Si vous avez plusieurs créateurs d'actions qui doivent être passés au composant enfant en tant qu'accessoires, une alternative consiste à les encapsuler avec bindActionCreators dans mapDispatchToProps (voir redux.js.org/docs/api/bindActionCreators.html ); une autre alternative consiste simplement à fournir un objet d'action aux créateurs pour se connecter (), par exemple, se connecter (mapStateToProps, {actioncreators}), react-redux les encapsulera avec dispatch () pour vous.
dave
81

C'est essentiellement un raccourci. Donc au lieu d'avoir à écrire:

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

Vous utiliseriez mapDispatchToProps comme indiqué dans votre exemple de code, puis écrivez ailleurs:

this.props.onTodoClick(id);

ou plus probablement dans ce cas, vous auriez cela en tant que gestionnaire d'événements:

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

Il y a une vidéo utile de Dan Abramov à ce sujet ici: https://egghead.io/lessons/javascript-redux-generating-containers-with-connect-from-react-redux-visibletodolist

hamstu
la source
Je vous remercie. Je me demande également, comment la répartition est-elle ajoutée aux accessoires en premier lieu?
Code Whisperer
14
Si vous ne fournissez pas votre propre mapDispatchfonction, Redux utilisera une fonction par défaut. Cette mapDispatchfonction par défaut prend simplement la dispatchréférence de la fonction et vous la donne en tant que this.props.dispatch.
markerikson
7
La méthode d'envoi est transmise par la composante fournisseur
Diego Haz
55

mapStateToProps()est un utilitaire qui aide votre composant à obtenir un état mis à jour (qui est mis à jour par d'autres composants),
mapDispatchToProps()est un utilitaire qui aidera votre composant à déclencher un événement d'action (action de répartition qui peut provoquer un changement d'état de l'application)

Saisurya Kattamuri
la source
23

mapStateToProps, mapDispatchToPropsEt connectde la react-reduxbibliothèque offre un moyen pratique d'accéder à votre stateet dispatchfonction de votre magasin. Donc, fondamentalement, la connexion est un composant d'ordre supérieur, vous pouvez également penser comme un wrapper si cela vous convient. Ainsi, chaque fois que votre statemodification mapStateToPropssera appelée avec votre nouveau stateet par la suite, lors de la propsmise à jour, le composant exécutera la fonction de rendu pour rendre votre composant dans le navigateur. mapDispatchToPropsstocke également les valeurs-clés sur le propscomposant, généralement elles prennent la forme d'une fonction. De cette façon, vous pouvez déclencher des statemodifications à partir de votre composant onClick, les onChangeévénements.

Depuis les documents:

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) 

Assurez-vous également que vous connaissez les fonctions sans état React et les composants d'ordre supérieur

Vlad Filimon
la source
Donc, l'envoi est comme un événement fondamentalement?
Code Whisperer du
2
Cela pourrait être lié à un événement, la répartition n'est qu'une fonction et le seul moyen de changer l' état de votre application . mapStateToProps est un moyen d'exposer la fonction de répartition de votre magasin à React Component. Notez également que la connexion ne fait pas partie de redux, en fait, c'est juste un utilitaire et une bibliothèque de réduction passe -partout appelée react-redux pour fonctionner avec react et redux. Vous pouvez obtenir le même résultat sans react-redux si vous passez votre magasin du composant root react aux enfants.
Vlad Filimon
3

mapStateToPropsreçoit le stateet propset vous permet d'extraire les accessoires de l'état à passer au composant.

mapDispatchToPropsreçoit dispatchet propsest destiné à vous de lier les créateurs d'actions à la répartition. Ainsi, lorsque vous exécutez la fonction résultante, l'action est distribuée.

Je trouve que cela vous évite d'avoir à faire dispatch(actionCreator())dans votre composant, ce qui le rend un peu plus facile à lire.

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

Harry Moreno
la source
Merci mais quelle est la valeur de la dispatchméthode? D'où est ce que ça vient?
Code Whisperer
Oh. La répartition fait essentiellement démarrer l'action le flux unidirectionnel redux / flux. Les autres réponses semblent avoir mieux répondu à votre question.
Harry Moreno
En outre, la méthode d'expédition provient de l'amélioration fournie par <Provider/>lui - même. Il fait sa propre magie de composants de haut niveau afin de garantir que la répartition est disponible dans ses composants enfants.
Ricardo Magalhães
3

Supposons maintenant qu'il existe une action pour redux comme:

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

Lorsque vous l'importez,

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

Comme le nom de la fonction le dit mapDispatchToProps(), mappez l' dispatchaction sur les accessoires (les accessoires de notre composant)

L'hélice onTodoClickest donc une clé de mapDispatchToPropsfonctionnement que les délégués doivent acheminer addTodo.

Aussi, si vous souhaitez couper le code et contourner l'implémentation manuelle, vous pouvez le faire,

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

Ce qui signifie exactement

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}
Rencontrez Zaveri
la source