web-dev-qa-db-fra.com

Qu'est-ce que mapDispatchToProps?

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 méthode dispatch() et renvoie les accessoires de rappel que vous souhaitez injecter dans le composant de présentation.

Cela n'a aucun sens. Pourquoi avez-vous besoin de mapDispatchToProps alors que vous 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 comment cette fonction est et pourquoi elle est utile?

311
Code Whisperer

Je pense qu'aucune des réponses n'a cristallisé la raison pour laquelle mapDispatchToProps est utile.

On ne peut vraiment répondre à cette question que dans le contexte du modèle container-component, que j'ai mieux compris en première lecture: Container Components alors tilisation avec React .

En un mot, vos components sont censés se préoccuper uniquement d’afficher des éléments. Le seul endroit où ils sont supposés obtenir des informations est leur accessoire .

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

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

C’est ce que sont les containers.

Par conséquent, un "bien conçu" component dans le motif 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 récupère les informations qu'il affiche des accessoires (provenant du magasin redux via mapStateToProps) et obtient également sa fonction d'action de ses accessoires: sendTheAlert().

C'est là que mapDispatchToProps entre: dans le container correspondant

// 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 la container1 qui connaît Redux, dispatch, store and state et ... des trucs.

La component du motif, FancyAlerter, qui effectue le rendu, n'a pas besoin de savoir quoi que ce soit de ce genre de choses: elle appelle sa méthode à l'appel à onClick du bouton, via son les accessoires.

Et ... mapDispatchToProps était le moyen utile fourni par redux pour permettre au conteneur de passer facilement cette fonction au composant encapsulé sur ses accessoires.

Tout cela ressemble beaucoup à l'exemple de todo dans la documentation, et à une autre réponse ici, mais j'ai essayé de l'exprimer à la lumière du motif pour souligner pourquoi .

(Remarque: vous ne pouvez pas utiliser mapStateToProps dans le même but que mapDispatchToProps pour la raison fondamentale pour laquelle vous n'avez pas accès à dispatch à l'intérieur de mapStateToProp. 'pas utiliser mapStateToProps pour 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é préférable d'avoir mapToProps(state, dispatch, props) IE une fonction pour faire les deux!


1 Notez que j'ai délibérément appelé explicitement le conteneur FancyButtonContainer, pour souligner qu'il s'agit d'une "chose" - l'identité (et donc l'existence!) Du conteneur. comme "une chose" est parfois perdue dans le raccourci

export default connect(...)

syntaxe indiquée dans la plupart des exemples

524
GreenAsJade

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

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

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

this.props.onTodoClick(id);

ou plus probablement dans ce cas, vous auriez cela comme gestionnaire d'événement:

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

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

70
hamstu

mapStateToProps() est un utilitaire qui aide votre composant à obtenir l'é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 distribution pouvant entraîner un changement de l'état de l'application).

48

mapStateToProps, mapDispatchToProps et connect à partir de la bibliothèque react-redux fournit un moyen pratique d'accéder à votre fonction state et dispatch de votre magasin. Donc, fondamentalement, connect est un composant d'ordre supérieur, vous pouvez également penser comme un wrapper si cela vous semble judicieux. Ainsi, chaque fois que votre state sera modifié, mapStateToProps sera appelé avec votre nouveau state et ultérieurement, lorsque vous _ props le composant de mise à jour exécutera la fonction de rendu pour rendre votre composant dans le navigateur. mapDispatchToProps stocke également les valeurs-clés sur le props de votre composant; elles prennent généralement la forme d'une fonction. De cette manière, vous pouvez déclencher state changement à partir de votre événement onClick, onChange de votre composant.

De docs:

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 bien fonctions React stateless et composants d'ordre supérieur

18
Vlad Filimon

mapStateToProps reçoit les state et props et vous permet d'extraire des propriétés de l'état à transmettre au composant.

mapDispatchToProps reçoit dispatch et props et vous permet de lier les créateurs d'action à l'envoi afin que l'action soit envoyée lorsque vous exécutez la fonction résultante.

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

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

2
Harry Moreno

Supposons maintenant qu’il existe une action pour redux telle que:

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

Quand 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 indique mapDispatchToProps(), mappez dispatch l'action sur les accessoires (les accessoires de notre composant)

Ainsi, prop onTodoClick est une clé pour mapDispatchToProps fonction qui délègue furthere à l’action d’envoi addTodo.

Aussi, si vous voulez 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())
      }
    }
}
1
Meet Zaveri