Utilisation de la fonction connect () de react-redux

L'article que nous traduisons aujourd'hui expliquera comment créer des composants de conteneur dans des applications React liées à l'état de Redux. Ce matériel est basé sur la description du mécanisme de gestion d'état dans React à l'aide du package react-redux . Il est supposé que vous avez déjà une compréhension de base de l'architecture et de l'API des bibliothèques dont nous parlerons. Si ce n'est pas le cas, consultez la documentation React et Redux .

image

À propos de la gestion des états dans les applications JavaScript


React fournit au développeur deux mécanismes principaux pour transférer des données vers des composants. Ce sont les propriétés (accessoires) et l'état. Les propriétés sont en lecture seule et permettent aux composants parents de transmettre des attributs aux composants enfants. Un état est une entité locale encapsulée dans un composant qui peut changer à tout moment du cycle de vie du composant.

Étant donné que l'état est un mécanisme extrêmement utile utilisé pour créer de puissantes applications React dynamiques, il est nécessaire de le gérer correctement. Il existe actuellement plusieurs bibliothèques qui fournissent une architecture bien structurée pour gérer l'intégrité des applications. Parmi eux, Flux , Redux , MobX .

Redux est une bibliothèque conçue pour créer des conteneurs utilisés pour stocker l'état de l'application. Il offre au développeur des outils de gestion d'état compréhensibles qui se comportent de manière prévisible. Cette bibliothèque convient aux applications écrites en JavaScript pur, ainsi qu'aux projets dans le développement desquels certains frameworks ont été utilisés. Redux est de petite taille, mais il vous permet d'écrire des applications fiables qui fonctionnent dans différents environnements.

Voici comment créer des référentiels Redux:

import { createStore } from 'redux'; const initialState = {    auth: { loggedIn: false } } const store = createStore((state = initialState, action) => {    switch (action.type) {        case "LOG_IN":            return { ...state, auth: { loggedIn: true } };            break;        case "LOG_OUT":            return { ...state, auth: { loggedIn: false } };            break;        default:            return state;            break;    }    }) 

Package React-redux


Le package react-redux fournit des liaisons React pour le conteneur d'état Redux, ce qui rend extrêmement facile la connexion de l'application React au référentiel Redux. Cela vous permet de séparer les composants d'une application React en fonction de leur relation avec le référentiel. À savoir, nous parlons des types de composants suivants:

  1. Composants de présentation. Ils ne sont responsables que de l'apparence de l'application et ne sont pas au courant de l'état de Redux. Ils reçoivent des données via des propriétés et peuvent appeler des rappels, qui leur sont également transmis via des propriétés.
  2. Composants de conteneur. Ils sont responsables du fonctionnement des mécanismes internes de l'application et interagissent avec l'état de Redux. Ils sont souvent créés en utilisant react-redux, ils peuvent envoyer des actions Redux. De plus, ils souscrivent aux changements d'état.

Des détails sur cette approche de la répartition des responsabilités des composants sont disponibles ici . Dans cet article, nous parlerons principalement des composants de conteneur connectés à l'état Redux à l'aide de react-redux.

Le paquet react-redux a une interface très simple. En particulier, la chose la plus intéressante à propos de cette interface se résume à ce qui suit:

  1. <Provider store> - vous permet de créer un wrapper pour une application React et de rendre l'état Redux disponible pour tous les composants de conteneur dans sa hiérarchie.
  2. connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) - vous permet de créer des composants d'ordre supérieur. Cela est nécessaire pour créer des composants de conteneur basés sur les composants de base de React.

Installez react-redux afin d'utiliser ce package dans le projet comme suit:

 npm install react-redux --save 

En supposant que vous avez déjà configuré le référentiel Redux pour votre application React, voici un exemple de connexion de l'application au référentiel Redux:

 import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import createStore from './createReduxStore'; const store = createStore(); const rootElement = document.getElementById('root'); ReactDOM.render(( <Provider store={store}>   <AppRootComponent /> </Provider> ), rootElement); 

Vous pouvez maintenant créer des composants de conteneur connectés au référentiel Redux. Cela se fait dans la hiérarchie de AppRootComponent à l'aide de l'API connect() .

Quand utiliser connect ()?


▍Création de composants de conteneurs


Comme déjà mentionné, l'API react-redux connect() est utilisée pour créer des composants de conteneur qui sont connectés au référentiel Redux. Le stockage auquel vous vous connectez est obtenu à partir de l'ancêtre le plus élevé du composant à l'aide du mécanisme de contexte React. La fonction connect() n'est pas nécessaire si vous créez uniquement des composants de présentation.

Si vous, dans le composant React, avez besoin de recevoir des données du stockage, ou si vous devez envoyer des actions, ou si vous devez faire les deux, vous pouvez convertir un composant normal en composant conteneur en l'enveloppant dans un composant d'ordre supérieur renvoyé par connect() partir de réagir-redux. Voici à quoi ça ressemble:

 import React from 'react'; import { connect } from 'react-redux'; import Profile from './components/Profile'; function ProfileContainer(props) { return (   props.loggedIn     ? <Profile profile={props.profile} />     : <div>Please login to view profile.</div> ) } const mapStateToProps = function(state) { return {   profile: state.user.profile,   loggedIn: state.auth.loggedIn } } export default connect(mapStateToProps)(ProfileContainer); 

▍ Élimination de la nécessité de s'abonner manuellement au stockage Redux


Vous pouvez créer le composant conteneur vous-même et signer manuellement le composant sur le référentiel Redux à l'aide de la commande store.subscribe() . Cependant, l'utilisation de la fonction connect() signifie l'application de certaines améliorations et optimisations de performances que vous ne pourrez peut-être pas utiliser lors de l'utilisation d'autres mécanismes.

Dans l'exemple suivant, nous essayons de créer manuellement un composant conteneur et de le connecter au référentiel Redux en vous y abonnant. Ici, nous nous efforçons d'implémenter la même fonctionnalité que celle illustrée dans l'exemple précédent.

 import React, { Component } from 'react'; import store from './reduxStore'; import Profile from './components/Profile'; class ProfileContainer extends Component { state = this.getCurrentStateFromStore() getCurrentStateFromStore() {   return {     profile: store.getState().user.profile,     loggedIn: store.getState().auth.loggedIn   } } updateStateFromStore = () => {   const currentState = this.getCurrentStateFromStore();     if (this.state !== currentState) {     this.setState(currentState);   } } componentDidMount() {   this.unsubscribeStore = store.subscribe(this.updateStateFromStore); } componentWillUnmount() {   this.unsubscribeStore(); } render() {   const { loggedIn, profile } = this.state;     return (     loggedIn       ? <Profile profile={profile} />       : <div>Please login to view profile.</div>   ) } } export default ProfileContainer; 

La fonction connect() , en outre, offre au développeur une flexibilité supplémentaire, vous permettant de configurer les composants de conteneur pour recevoir des propriétés dynamiques en fonction des propriétés qui leur ont été transmises à l'origine. Cela s'avère très utile pour obtenir des sélections à partir d'un état basé sur des propriétés, ou pour lier des générateurs d'actions à une variable spécifique à partir de propriétés.

Si votre application React utilise plusieurs référentiels Redux, connect() facilite la spécification du référentiel spécifique auquel le composant conteneur doit être connecté.

Anatomy connect ()


La fonction connect() fournie par le package react-redux peut prendre jusqu'à quatre arguments, chacun étant facultatif. Après avoir appelé la fonction connect() , un composant d'ordre supérieur est renvoyé qui peut être utilisé pour encapsuler n'importe quel composant React.

Étant donné que la fonction renvoie un composant d'ordre supérieur, elle doit être appelée à nouveau, en passant le composant React de base afin de le convertir en composant conteneur:

 const ContainerComponent = connect()(BaseComponent); 

Voici la signature de la fonction connect() :

 connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) 

▍ Argument mapStateToProps


L'argument mapStateToProps est une fonction qui renvoie un objet normal ou une autre fonction. La transmission de cet argument connect() souscrit le composant conteneur aux mises à jour du référentiel Redux. Cela signifie que la fonction mapStateToProps sera appelée chaque fois que l'état du référentiel change. Si vous n'êtes pas intéressé par la surveillance des mises à jour d'état, transmettez connect() comme valeur de cet argument à undefined ou null .

La fonction mapStateToProps déclarée avec deux paramètres, dont le second est facultatif. Le premier paramètre est l'état actuel du référentiel Redux. Le deuxième paramètre, s'il est transmis, est un objet des propriétés transmises au composant:

 const mapStateToProps = function(state) { return {   profile: state.user.profile,   loggedIn: state.auth.loggedIn } } export default connect(mapStateToProps)(ProfileComponent); 

Si un objet normal est renvoyé par mapStateToProps , alors l'objet stateProps renvoyé stateProps combiné avec les propriétés du composant. Vous pouvez accéder à ces propriétés dans le composant comme suit:

 function ProfileComponent(props) { return (   props.loggedIn     ? <Profile profile={props.profile} />     : <div>Please login to view profile.</div> ) } 

Si mapStateToProps renvoie une fonction, cette fonction est utilisée comme mapStateToProps pour chaque instance du composant. Cela peut être utile pour améliorer les performances de rendu et pour la mémorisation.

Argument Argument mapDispatchToProps


L'argument mapDispatchToProps peut être soit un objet soit une fonction qui renvoie soit un objet normal soit une autre fonction. Afin de mieux illustrer mapDispatchToProps , nous avons besoin de générateurs d'actions. Supposons que nous ayons les générateurs suivants:

 export const writeComment = (comment) => ({ comment, type: 'WRITE_COMMENT' }); export const updateComment = (id, comment) => ({ id, comment, type: 'UPDATE_COMMENT' }); export const deleteComment = (id) => ({ id, type: 'DELETE_COMMENT' }); 

Considérez maintenant les diverses utilisations de mapDispatchToProps .

Implémentation par défaut par défaut


Si vous n'utilisez pas votre propre implémentation mapDispatchToProps , représentée par un objet ou une fonction, une implémentation standard sera utilisée, qui implémentera la méthode du référentiel dispatch() tant que propriété du composant. Vous pouvez utiliser cette propriété dans un composant comme celui-ci:

 import React from 'react'; import { connect } from 'react-redux'; import { updateComment, deleteComment } from './actions'; function Comment(props) { const { id, content } = props.comment; //    props.dispatch() const editComment = () => props.dispatch(updateComment(id, content)); const removeComment = () => props.dispatch(deleteComment(id)); return (   <div>     <p>{ content }</p>     <button type="button" onClick={editComment}>Edit Comment</button>     <button type="button" onClick={removeComment}>Remove Comment</button>   </div> ) } export default connect()(Comment); 

Transfert d'objets


Si un objet est utilisé comme argument pour mapDispatchToProps , chaque fonction de l'objet sera considérée comme un générateur d'actions Redux et encapsulée dans un appel de méthode de référentiel dispatch() , ce qui lui permettra d'être appelé directement. L'objet résultant avec des générateurs d'actions, dispatchProps , sera combiné avec les propriétés du composant.

L'exemple suivant montre un exemple de construction de l'argument mapDispatchToProps , qui est un objet avec des générateurs d'actions, ainsi que la façon dont les générateurs peuvent être utilisés comme propriétés du composant React:

 import React from 'react'; import { connect } from 'react-redux'; import { updateComment, deleteComment } from './actions'; function Comment(props) { const { id, content } = props.comment; // ,   ,   const editComment = () => props.updatePostComment(id, content); const removeComment = () => props.deletePostComment(id); return (   <div>     <p>{ content }</p>     <button type="button" onClick={editComment}>Edit Comment</button>     <button type="button" onClick={removeComment}>Remove Comment</button>   </div> ) } //     const mapDispatchToProps = { updatePostComment: updateComment, deletePostComment: deleteComment } export default connect(null, mapDispatchToProps)(Comment); 

Transfert de fonction


Lors de l'utilisation de la fonction mapDispatchToProps comme argument mapDispatchToProps le programmeur doit veiller à renvoyer l'objet dispatchProps , qui lie les générateurs d'actions à l'aide de la méthode de stockage dispatch() . Cette fonction accepte, comme premier paramètre, la méthode du référentiel dispatch() . Comme avec mapStateToProps , la fonction peut également accepter le deuxième paramètre facultatif ownProps , qui décrit le mappage avec les propriétés d'origine transmises au composant.

Si cette fonction renvoie une autre fonction, la fonction renvoyée est utilisée comme mapDispatchToProps , ce qui peut être utile pour améliorer les performances de rendu et la mémorisation.

La fonction d'assistance bindActionCreators() de Redux peut être utilisée à l'intérieur de cette fonction pour lier des générateurs d'actions à la méthode du référentiel dispatch() .

L'exemple suivant montre l'utilisation, dans le rôle de mapDispatchToProps , d'une fonction. Il montre également le travail avec la fonction auxiliaire bindActionCreators() , qui est utilisée pour lier les générateurs d'actions pour travailler avec des commentaires sur les props.actions du composant React:

 import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import * as commentActions from './actions'; function Comment(props) { const { id, content } = props.comment; const { updateComment, deleteComment } = props.actions; //    props.actions const editComment = () => updateComment(id, content); const removeComment = () => deleteComment(id); return (   <div>     <p>{ content }</p>     <button type="button" onClick={editComment}>Edit Comment</button>     <button type="button" onClick={removeComment}>Remove Comment</button>   </div> ) } const mapDispatchToProps = (dispatch) => { return {   actions: bindActionCreators(commentActions, dispatch) } } export default connect(null, mapDispatchToProps)(Comment); 

▍Argument mergeProps


Si l'argument mergeProps est passé à connect() , alors c'est une fonction qui prend les trois paramètres suivants:

  • stateProps est l'objet de propriété renvoyé par l'appel mapStateToProps() .
  • dispatchProps - un objet de propriété avec des générateurs d' mapDispatchToProps() de mapDispatchToProps() .
  • ownProps - Les propriétés d'origine obtenues par le composant.

Cette fonction renvoie un objet simple avec des propriétés qui seront transmises au composant encapsulé. Ceci est utile pour mapper conditionnellement une partie de l'état d'un référentiel Redux ou de générateurs d'actions basés sur des propriétés.

Si connect() ne transmet pas cette fonction, son implémentation standard est utilisée:

 const mergeProps = (stateProps, dispatchProps, ownProps) => { return Object.assign({}, ownProps, stateProps, dispatchProps) } 

▍Argument représentant un objet avec des paramètres


Un objet facultatif, transmis à la fonction connect() comme quatrième argument, contient des paramètres conçus pour changer le comportement de cette fonction. Ainsi, connect() est une implémentation spéciale de la fonction connectAdvanced() , il accepte la plupart des paramètres disponibles pour connectAdvanced() , ainsi que certains paramètres supplémentaires.

Voici la page de documentation, après avoir lu, vous pouvez découvrir quels paramètres peuvent être utilisés avec connect() , et comment ils modifient le comportement de cette fonction.

Utilisation de la fonction connect ()


▍Créer un stockage


Avant de convertir un composant React normal en composant conteneur à l'aide de connect() , vous devez créer un référentiel Redux auquel ce composant sera connecté.

Supposons que nous ayons un composant conteneur NewComment , qui est utilisé pour ajouter de nouveaux commentaires à la publication et, en outre, affiche un bouton pour envoyer des commentaires. Le code décrivant ce composant peut ressembler à ceci:

 import React from 'react'; import { connect } from 'react-redux'; class NewComment extends React.Component { input = null writeComment = evt => {   evt.preventDefault();   const comment = this.input.value;     comment && this.props.dispatch({ type: 'WRITE_COMMENT', comment }); } render() {   const { id, content } = this.props.comment;     return (     <div>       <input type="text" ref={e => this.input = e} placeholder="Write a comment" />       <button type="button" onClick={this.writeComment}>Submit Comment</button>     </div>   ) } } export default connect()(NewComment); 

Pour que ce composant soit utilisé dans l'application, il sera nécessaire de décrire le référentiel Redux auquel ce composant doit être connecté. Sinon, une erreur se produira. Cela peut se faire de deux manières, que nous allons maintenant examiner.

Définition de la propriété de magasin dans un composant conteneur


La première façon d'équiper un composant d'un référentiel Redux est de passer un lien vers un tel référentiel comme valeur de la propriété store du composant:

 import React from 'react'; import store from './reduxStore'; import NewComment from './components/NewComment'; function CommentsApp(props) { return <NewComment store={store} /> } 

Définition de la propriété store dans le composant <Provider>


Si vous souhaitez définir le référentiel Redux pour l'application une seule fois, vous serez intéressé par la méthode que nous allons maintenant examiner. Il convient généralement aux applications qui n'utilisent qu'un seul référentiel Redux.

Le package react-redux fournit au développeur le composant <Provider> , qui peut être utilisé pour encapsuler le composant racine de l'application. Il accepte la propriété du store . Il est supposé qu'il s'agit d'un lien vers le référentiel Redux, qui devrait être utilisé dans l'application. La propriété store est transmise, conformément à la hiérarchie d'application, aux composants du conteneur, à l'aide du mécanisme de contexte React:

 import React from 'react'; import ReactDOM from 'react-dom'; import store from './reduxStore'; import { Provider } from 'react-redux'; import NewComment from './components/NewComment'; function CommentsApp(props) { return <NewComment /> } ReactDOM.render(( <Provider store={store}>   <CommentsApp /> </Provider> ), document.getElementById('root')) 

AccessOpenProps Access Organization


Comme déjà mentionné, les fonctions mapStateToProps et mapDispatchToProps mapStateToProps à connect() peuvent être déclarées avec le deuxième paramètre ownProps , qui est les propriétés du composant.
Cependant, il y a un problème. Si le nombre de paramètres requis de la fonction déclarée est inférieur à 2, alors ownProps ne sera pas transmis. Mais si une fonction est déclarée sans paramètres obligatoires ou avec au moins 2 paramètres, ownProps sera transmis.

Considérez plusieurs options pour travailler avec ownProps .

Déclaration de fonction sans paramètres


 const mapStateToProps = function() { console.log(arguments[0]); // state console.log(arguments[1]); // ownProps }; 

Dans cette situation, ownProps transmis, car la fonction est déclarée sans les paramètres requis. Par conséquent, le code suivant écrit à l'aide de la nouvelle syntaxe pour les paramètres ES6 restants fonctionnera:

 const mapStateToProps = function(...args) { console.log(args[0]); // state console.log(args[1]); // ownProps }; 

Déclaration de fonction avec un paramètre


Prenons l'exemple suivant:

 const mapStateToProps = function(state) { console.log(state); // state console.log(arguments[1]); // undefined }; 

Il n'y a qu'un seul paramètre, l' state . Par conséquent, arguments[1] prend la valeur undefined raison du fait que ownProps pas transmis.

Déclaration de fonction avec paramètre par défaut


 const mapStateToProps = function(state, ownProps = {}) { console.log(state); // state console.log(ownProps); // {} }; 

Il n'y a qu'un seul paramètre obligatoire, state , car le deuxième paramètre, ownProps , est facultatif car il a une valeur par défaut. Par conséquent, comme il n'y a qu'un seul paramètre requis, ownProps pas transmis et le mappage est effectué avec la valeur par défaut qui lui a été affectée, c'est-à-dire avec un objet vide.

Déclarer une fonction avec deux paramètres


 const mapStateToProps = function(state, ownProps) { console.log(state); // state console.log(ownProps); // ownProps }; 

Tout est arrangé très simplement. A savoir, dans une telle situation, le transfert de ownProps du fait que la fonction est déclarée avec deux paramètres requis.

Résumé


Après avoir maîtrisé ce matériel, vous avez appris quand et comment utiliser l'API connect() fournie par le package react-redux et conçue pour créer des composants de conteneur connectés à l'état Redux. Ici, nous avons parlé en détail de la structure de la fonction connect() et de la façon de l'utiliser, cependant, si vous souhaitez en savoir plus sur ce mécanisme, en particulier, vous familiariser avec ses cas d'utilisation, consultez cette section de la documentation react-redux.

Chers lecteurs! Utilisez-vous react-redux dans vos projets?

Source: https://habr.com/ru/post/fr423157/


All Articles