Fermer

septembre 11, 2018

Quand implémenter Redux dans votre application React


React est excellent pour restituer les composants et améliorer les performances, mais il manque tout modèle formel autour de l'état et de la récupération des données. Redux peut vous aider à résoudre certains problèmes liés à l’augmentation de la taille de votre application Web.

Vous avez donc lancé un nouveau projet et créé des composants React. Vous n'avez pas à aller très loin avant de devoir résoudre le problème de la gestion de vos données frontales. Ce n'est pas un problème particulièrement intéressant à résoudre, mais c'est une nécessité si vous voulez créer une application Web performante, performante, évolutive et évolutive.

React bénéficie d'excellentes performances grâce à son approche hiérarchique du stockage des données. et rendu d'éléments web. Malheureusement, cet avantage même rend la gestion des données compliquée et peut rapidement conduire à un gonflement du code. C'est là que Redux peut vous aider. Redux gère les données entre les composants en les séparant de la hiérarchie React.

L’architecture de Redux repose sur un flux de données unidirectionnel, qui s’associe parfaitement au modèle de rendu de React. Étant donné que le flux de données est unidirectionnel, nous n'avons pas à nous soucier des effets secondaires et pouvons nous attendre à ce que le composant soit rendu ou rendu de manière prévisible et réactive.

tâche de résoudre les problèmes de gestion des données de React, mais les avis divergent sur le moment où vous devez le mettre en œuvre. Un camp pense que vous ne devriez pas installer Redux tant que vous n’avez pas de problème de gestion de données. Le deuxième camp soutient que, puisque vous aurez probablement besoin d’un outil de gestion de l’état au cours du développement de votre application, vous devriez utiliser Redux dès le début. Ni l'un ni l'autre camp n'est nécessairement correct ou faux, mais je suis définitivement dans la seconde et voici la réponse courte: Il est plus facile de créer de bons modèles au début d'un projet que de changer votre paradigme de gestion des données. , vos modèles de développement, une fois que l'application a grandi. Il n’est pas toujours facile de voir votre projet trop compliqué avant qu’il ne soit trop tard. Néanmoins, quel que soit le camp dans lequel vous vous trouvez, vous pourrez utiliser certains des schémas ci-dessous, alors sautez!

Ci-dessous, j'ai créé un simple gestionnaire de contacts dans React. Vous remarquerez que j’ai enlevé une partie du contenu des fonctions, mais ne vous inquiétez pas: vous pouvez extraire le code et voir tous les détails à la fin. Pour le moment, concentrons-nous sur la structure.

// index.js

import React from 'react' ;

import ReactDOM de 'react-dom' ;

[19659003] import './ index.css' ;

importation depuis './ App' ;

ReactDOM.render (document.getElementById ( 'root' ));

// App.js

Import React, {Component} from 'Réagir';

Import {Contact} de './Contact';

classe App étend le composant {

constructeur (accessoires) {

[19659003] super (accessoires);

] this .state = {

selectedIndex: 0,

liste de contacts: [ …  ]

};

}

] _onContactSelected = (contactId) => {

// définit selectedIndex et contactId sur l'état pour une utilisation rapide access

}

_onContactUpdated = ( updatedContact) => {

// met à jour le contact [19659003]

}

render () {

const {contactList, selectedContactId, selectedIndex} = this .state;

return [

<div className = "App" >

<header className = "app-header" >

<img src = {logo} className = "app-logo" alt = "logo" /> [19659003]

<h1 className = "app-title" > Liste de contacts

19659003]

<Contacts

contactList = {contactList} 19659003]

selectedContactId = {selectedContactId}

selectedContact = { this .state.contactList [selectedIndex]}

onUpdate = { this ._ onContactUpdated}

onContactSelected = {[19659097] this ._ onContactSélectionnée

/>

)

} [19459] 003]

}

Le composant Contacts affiche une liste de contacts que l'utilisateur peut afficher et mettre à jour si nécessaire. Si c'est la seule fonctionnalité que nous prévoyons de créer, notre application n'a pas besoin de Redux. Mais disons que nous savons que nous allons ajouter une fonctionnalité de calendrier, le partage de contacts, l’authentification et, si tout va bien, l’intégration avec d’autres clients de messagerie tels que Skype et Facebook Messenger. Avec des fonctionnalités comme celles-ci sur la feuille de route, nous avons beaucoup de nouvelles fonctionnalités à créer, et plusieurs de nos nouvelles pages devront avoir accès aux mêmes données de base. Configurez maintenant Redux pour éviter de le retravailler plus tard.

Premièrement, nous devrons ajouter quelques nouvelles dépendances à notre projet:

npm install redux rea-redux redux-thunk

React-Redux est la liaison Redux pour React. Redux Thunk nous permettra d’utiliser des promesses dans nos actions au lieu de renvoyer des objets JSON purs.

Ensuite, nous devrons modifier notre index.js en créant le magasin Redux et en ajoutant le composant Redux Provider. Le fournisseur rendra notre magasin Redux accessible à tous les composants enfants.

// index.js

import React from [19659011] "réagir" ;

import ReactDOM de 'react-dom' ;

import './ index.css' ;

]

importation depuis './ App' ;

import {Provider} from 'react-redux' ; // liaisons redux pour réaction

importation de 'redux-thunk' ; // middleware permettant d'utiliser des promesses pour des actions asynchrones

import {createStore, applyMiddleware, compose} de [19659011] 'redux' ; // nous permet de créer le magasin et le middleware

réducteurs à l'importation de './ réducteurs /index.js';

const middleware = [thunk];

const store = createStore (réducteurs, {}, composez (applyMiddleware (... middleware)));

[19659026]

ReactDOM.render (

document.getElementById ( 'root' [19659012]));

Nous sommes maintenant prêts à connecter des composants au magasin Redux. Nous allons commencer dans App.js en mappant les actions pour commencer. Nous savons que lorsque notre application se charge, nous voulons envoyer une action qui récupère et charge tous nos contacts existants.

Une note rapide sur la répartition: la répartition est la méthode de Redux pour changer d’état. Il est important de noter que seules les actions appelées avec Dispatch peuvent modifier l'état dans Redux.

Pour ce faire, nous aurons la méthode du cycle de vie componentDidMount à appeler notre méthode getContacts. La raison pour laquelle nous appelons getContacts sur App.js par opposition à l'intérieur de Contact.js est que les Contacts sont globaux, donc quel que soit le composant appelé, nous voulons toujours que les contacts soient chargés.

// App.js

[19659003] import {connect} from 'react-redux' ;

import { getContacts} from './ actions' ;

classe App étend Composant {

mapDispatchToProps = (dispatch) => {

retour {

getContacts: ( ) => dispatch (getContacts ())

}

}

constructeur (accessoires) {

super (accessoires);

}

async componentDidMount () {

const { getContact} = this .props;

[19659003] wait getContacts ();

}

render () {

[19659026]

retour (

19659054] <div className = "App" >

"App-header" >

<img src = {logo} className = "App-logo" alt = "logo" />

<h1 className = "Titre de l'application" > Liste de contacts

)

}

}

const ConnectedApp = connect ( null [19659012]App.mapDispatchToProps) (App);

export default ConnectedApp;

]

Maintenant que App.js est connecté, nous pouvons nous concentrer sur Contacts.js. Nous commençons par ajouter mapStateToProps et mapDispatchToProps, puis en les connectant via le composant Connect HOC (Higher Order Component).

// Contacts.js

Import React, {Composant, Fragment} de 'réagir';

Importer {connect} de 'react-redux';

import {updateContact} from '../ actions' ;

La classe Contacts étend le composant {

statique mapStateToProps = (state, ownProps) => {

const {contacts} = etat;

contre t contactList = Object.values ​​(contacts.byId);

retour {

contactList,

contactsById: contacts.byId

};

}

static mapDispatchToProps = (dispatch) => {

retour {

updateContact: (params) => dispatch (updateContact (params)) [19659003]

}

19659042]};

constructeur (accessoires) {

super (accessoires);

this .state = {

] selectedContactId: null

};

}

_onContactSelected = (contactId) => {

this .setState ({selectedContactId: contactId});

[19659003] }

_onContactUpdated = (contact ) => {

const {updateContact} = this .props;

updateContact ({contact});

} ]

render () {

const {contactList, contactsById} = this .props;

const {selectedContactId} = this .state;

let selectedContact = {};

si (selectedContactId) {

[19659003] selectedContact = contactsById [selectedContactId];

retour (

]

<ContactList contactList = {contactList} onContactSelected = { this . _onContactSelected} selectedContactId = {selectedContactId} />

9459003]


<EditContact contact = {selectedContact} onUpdate = { this ._ onContactUpdated} />

)

}

]}

const ConnectedContacts = connect (Contacts.mapStateToProps, Contacts.mapDispatchToProps) (Contacts);

export par défaut ConnectedContacts;

Jusqu'à présent, Contacts.js est le premier composant à implémenter à la fois mapStateToProps et mapDispatchToProps. Redux transmet à la fois la fonction et le props du composant actuel à la fonction mapStateToProps. Cela permet de récupérer et de mapper les données aux accessoires du composant actuel. MapDispatchToProps nous permet d'envoyer des actions à Redux pour stocker des données ou effectuer des appels HTTP que nous avons définis dans des actions. C'est une méthode non standard d'implémentation des fonctions Redux. Mais l’un des principaux avantages est que ceci permet à mapStateToProps d’être testable par unité sans l’exporter explicitement.

Nous avons introduit le concept d’action dans notre discussion du composant ConnectedContacts, mais nous n’en avons pas vraiment parlé. Alors faisons cela maintenant. Le meilleur moyen de penser à une action est toute opération pouvant modifier l’état Redux. La plupart de ces actions seront des appels HTTP, des appels pour récupérer des données du stockage local ou même des appels à lire à partir de cookies. La raison pour écrire de bonnes actions claires est essentielle à la création d'une bonne application Web, car cela vous encourage à modulariser votre code de manière à faciliter la réutilisation du code entre les composants et à permettre à votre code de s'auto-documenter. Cela dit, regardons nos actions.

// actions.js

export const updateContact = (params) => {

const {contact } = params;

retourner (dispatch) => {

const updatedContact = fetch (…);

dispatch ({19459009]

tapez: 'UPDATE_CONTACT'

charge utile: {

contact: updatedContact

[19659003]

)

[19659042]};

};

Dans Redux, toutes les actions doivent renvoyer un objet avec une propriété de type. Grâce au middleware Redux-Thunk, nous pouvons effectuer des opérations plus complexes, comme les appels asynchrones, au sein d'une fonction qui distribue une action. Cela nous permet de déplacer des appels HTTP de composants en actions et de garder notre code de composant propre.

// reducers / index.js

import {combineReducers} de 'redux' ;

import {ContactReducer} from ' ./ContactReducer';

const reducers = combineReducers ({

contacts: ContactReducer

}) ;

exportation défaut réducteurs;

// Réducteurs / ContactReducer.js

const initializeState = function ( )

retour {

byId: {}

};

}

const ContactReducer = (state = initializeState (), action) => {

let newById = {};

commutateur (action.type) {

affaire ' UPDATE_CONTACT ': {

const {contact = {}} = action.payload;

newById = {

... state.byId

]};

si (contact) {

[19659111] newById [contact.id] = contact;

19659003]

retour {

        ...state,

 

        byId: newById

 

      };

 

    }

 

    case 'GET_CONTACTS': {

 

      

 

    }

 

    default:

 

      return state;

 

  }

 

};

 

 

export { ContactReducer };

Actions don’t modify Redux state directly, though. That’s the reducer’s job. The type value that we passed from the action tells the reducer exactly what to do. The reducer then handles the payload passed by the action by storing the data in a specified shape. We’re not going to get into the specifics of state shape or data access here; it’s a pretty lengthy topic and would require a blog post all its own.

Throughout this post, I’ve written about “modifying” state. In truth, this is a bit of a misnomer. We never actually want to modify the Redux state directly. Instead, we always want to return a modified copy of the state tree. This concept of immutable state is a crucial—and often overlooked—detail when writing reducers.

With all the pieces in place, we have laid the foundation for our app to use Redux to manage state. Because Redux allows you to have access to the entire state tree from any component in your project, it’s easy to want to connect every component. This is a mistake. One of the most significant downsides to using Redux for all storage is the performance issues from having all components re-render based on global state. A good rule of thumb is that you want to have a single connected component with many unconnected components below the container level. It’s the container’s job to pass props to these unconnected components, just as you would in a typical React app. There are always exceptions, but you should strive to keep your components from being connected until it makes sense to connect them.

At this point, I hope you feel that Redux is not an overly complicated thing to implement and you feel comfortable throwing Redux into the simplest of web apps. Even if there is not a ton of data to manage, it helps break apart code into separate pieces that allows for more readable, maintainable code.

For More on React

For more information on React, check out the “All Things React” page, which features current updates, resources, tips and techniques, history, and other useful React information including links to the Kendo UI for React component library.

Source Code Links

* "Contact List Source Code (Github)": https://github.com/reedyrm/contact-list-example

* "Contact List Redux Source Code (Github)": https://github.com/reedyrm/contact-list-redux-example


Comments are disabled in preview mode.




Source link

Revenir vers le haut