Les crochets se remplacent-ils dans React Redux?

Depuis que les hooks sont apparus dans React, il y a eu de nombreuses questions pour savoir s'ils peuvent remplacer Redux.

Je crois que les crochets et Redux ont peu en commun. Les crochets ne nous donnent pas de nouvelles opportunités incroyables de travailler avec l'État. Au lieu de cela, ils étendent les API afin de pouvoir faire dans React ce qui était déjà possible. Cependant, l'API hook a rendu le travail avec les capacités de gestion d'état de React beaucoup plus pratique. Il s'est avéré qu'il est plus facile d'utiliser les nouvelles fonctionnalités pour travailler avec l'état que les anciennes qui étaient disponibles dans les composants basés sur les classes. Maintenant, j'utilise les outils pour travailler avec l'état des composants beaucoup plus souvent qu'auparavant. Naturellement, je ne fais cela que lorsque cela est approprié.



Afin d'expliquer mon attitude envers les hooks React et Redux, je voudrais d'abord parler des situations dans lesquelles Redux est généralement utilisé.

Qu'est-ce que Redux?


Redux est une bibliothèque qui implémente un stockage prévisible de l'état des applications. C'est également une architecture qui s'intègre parfaitement à React.

Voici les principaux atouts de Redux:

  • Représentation déterministe de l'état (en combinaison avec des composants purs, cela permet de former des éléments visuels déterministes).
  • Prise en charge des changements d'état transactionnels.
  • Isolement de la gestion de l'état des mécanismes d'E / S et des effets secondaires.
  • La présence d'une source unique de données fiables pour l'État.
  • Organisation aisée de la collaboration avec l'Etat en différents composants.
  • Outils d'analyse transactionnelle (journalisation automatique des objets d'action).
  • Débogage avec la possibilité d'enregistrer et de lire le processus d'exécution du programme (Time Travel Debugging, TTD).

En d'autres termes, Redux vous permet de bien organiser votre code et de le déboguer facilement. Redux aide à développer des applications faciles à maintenir. L'utilisation de cette bibliothèque facilite la recherche des sources de problèmes qui surviennent dans les programmes.

Que sont les crochets React?


Les crochets React permettent, lorsque vous travaillez avec des composants fonctionnels, d'utiliser un analogue de l'état des composants en fonction des classes et des analogues de leurs méthodes de cycle de vie. Des crochets sont apparus dans React 16.8.

Les principales forces des crochets sont les suivantes:

  • La possibilité d'utiliser l'état et de gérer les événements du cycle de vie des composants sans utiliser de composants basés sur les classes.
  • Stockage conjoint de la logique associée dans le même emplacement de composant au lieu de diviser une logique similaire entre plusieurs méthodes de cycle de vie.
  • Mécanismes de partage indépendants de l'implémentation du composant (similaire au modèle de prop de rendu ).

Notez que ces excellentes fonctionnalités ne dépassent pas, en fait, Redux. Les hooks React peuvent et doivent être utilisés pour effectuer des mises à jour d'état déterministe, mais cela a toujours été l'une des fonctionnalités de React, et le modèle d'état déterministe Redux se combine bien avec cette fonctionnalité. C'est ainsi que React parvient à un déterminisme dans la sortie des éléments visuels, et c'est, sans exagération, l'un des motifs moteurs de la création de React.

Si vous utilisez des outils tels que l'API react-redux avec prise en charge des hooks ou le hook React useReducer , vous constaterez qu'il n'y a aucune raison de demander quoi choisir - hooks ou Redux. Vous pouvez utiliser les deux, combiner et combiner ces technologies.

Qu'est-ce qui remplace les crochets?


Après l'avènement des API de hook, j'ai cessé d'utiliser les technologies suivantes:

  • Composants basés sur la classe.
  • Modèle de rendu-prop .

Qu'est-ce qui ne remplace pas les crochets?


J'utilise encore souvent les technologies suivantes:

  • Redux - pour toutes les raisons ci-dessus.
  • Composants d'ordre supérieur - dans le but d'effectuer la composition de composants dans les cas où je dois implémenter une fonctionnalité de bout en bout partagée par tout ou partie des composants visuels de l'application. Ces fonctionnalités incluent les fournisseurs Redux, les systèmes de mise en page, les systèmes de prise en charge des paramètres d'application, les outils d'authentification et d'autorisation, les outils d'internationalisation des applications, etc.
  • Séparation entre les composants du conteneur et les composants qui ont une représentation visuelle. Cela vous permet d'améliorer la modularité et la testabilité des applications, il est préférable de séparer les effets et la logique pure.

Quand utiliser des crochets?


Il n'est pas nécessaire de s'efforcer d'utiliser Redux dans chaque application et dans chaque composant. Si votre projet se compose d'un composant visuel, s'il n'enregistre pas de données et ne charge pas de données à partir de là, si des opérations d'E / S asynchrones n'y sont pas effectuées, je ne peux pas penser à une raison valable pour compliquer ce projet en utilisant Redux.

On peut en dire autant des composants qui présentent les caractéristiques suivantes:

  • Ils n'utilisent pas les ressources réseau.
  • Ils ne stockent pas de données dans l'état et ne les chargent pas à partir de là.
  • Ils ne partagent pas l'état avec d'autres composants qui ne sont pas leurs descendants.
  • Ils n'ont pas un certain état propre, utilisé pour le stockage de données à court terme.

Vous pouvez avoir de bonnes raisons d'utiliser le modèle d'état de composant React standard dans certaines situations. Dans des situations comme celle-ci, les crochets React vous feront du bon travail. Par exemple, le formulaire décrit ci-dessous utilise l'état local du composant à l'aide du hook React useState .

 import React, { useState } from 'react'; import t from 'prop-types'; import TextField, { Input } from '@material/react-text-field'; const noop = () => {}; const Holder = ({  itemPrice = 175,  name = '',  email = '',  id = '',  removeHolder = noop,  showRemoveButton = false, }) => {  const [nameInput, setName] = useState(name);  const [emailInput, setEmail] = useState(email); const setter = set => e => {    const { target } = e;    const { value } = target;    set(value);  }; return (    <div className="row">      <div className="holder">        <div className="holder-name">          <TextField label="Name">            <Input value={nameInput} onChange={setter(setName)} required />          </TextField>        </div>        <div className="holder-email">          <TextField label="Email">            <Input              value={emailInput}              onChange={setter(setEmail)}              type="email"              required            />          </TextField>        </div>        {showRemoveButton && (          <button            className="remove-holder"            aria-label="Remove membership"            onClick={e => {              e.preventDefault();              removeHolder(id);            }}          >            ×          </button>        )}      </div>      <div className="line-item-price">${itemPrice}</div>      <style jsx>{cssHere}</style>    </div>  ); }; Holder.propTypes = {  name: t.string,  email: t.string,  itemPrice: t.number,  id: t.string,  removeHolder: t.func,  showRemoveButton: t.bool, }; export default Holder; 

Ici, useState utilisé pour contrôler l'état brièvement utilisé des champs de saisie du name et de l' email - email :

 const [nameInput, setName] = useState(name); const [emailInput, setEmail] = useState(email); 

Vous pouvez remarquer qu'il existe toujours un créateur de l'action removeHolder entrant dans les propriétés de Redux. Comme déjà mentionné, la combinaison et la combinaison de technologies est tout à fait normale.

L'utilisation de l'état local d'un composant pour résoudre de tels problèmes a toujours semblé bonne, mais avant React hooks, j'aurais en tout cas voulu enregistrer les données du composant dans le stockage Redux et obtenir l'état des propriétés.

Auparavant, l'utilisation de l'état d'un composant impliquait l'utilisation de composants basés sur une classe, l'écriture des données initiales dans l'état à l'aide des mécanismes de déclaration des propriétés de classe (ou dans le constructeur de classe), etc. En conséquence, il s'est avéré que pour éviter d'utiliser Redux, le composant devait être trop compliqué. Redux s'est également prononcé en faveur de l'existence d'outils pratiques pour gérer l'état des formulaires à l'aide de Redux. Par conséquent, auparavant, je ne me serais pas inquiété que l'état temporaire du formulaire soit stocké au même endroit que les données avec une durée de vie plus longue.

Comme j'ai déjà utilisé Redux dans toutes mes applications plus ou moins complexes, le choix de la technologie pour stocker l'état des composants des composants ne m'a pas beaucoup fait réfléchir. Je viens d'utiliser Redux dans presque tous les cas.

Dans les conditions modernes, faire un choix est également facile: travailler avec l'état du composant est organisé à l'aide des mécanismes React standard et gérer l'état de l'application à l'aide de Redux.

Quand utiliser Redux?


Une autre question courante concernant la gestion des états est: «Dois-je absolument tout mettre dans le référentiel Redux? Si je ne le fais pas, cela violera-t-il la capacité de déboguer des applications à l'aide des mécanismes TTD? "

Il n'est pas nécessaire d'héberger absolument tout dans le référentiel Redux. Le fait est que les applications utilisent beaucoup de données temporaires qui sont trop dispersées autour d'elle pour donner des informations qui, étant enregistrées dans le journal ou utilisées pendant le débogage, peuvent fournir au développeur une aide importante pour trouver des problèmes. Probablement vous, sauf si vous écrivez une application d'édition en temps réel, vous n'avez pas besoin d'écrire à l'état chaque mouvement de souris ou chaque frappe de touche. Lorsque vous mettez quelque chose dans un état Redux, vous ajoutez un niveau d'abstraction supplémentaire à l'application, ainsi qu'un niveau supplémentaire de complexité qui l'accompagne.

En d'autres termes, vous pouvez utiliser Redux en toute sécurité, mais il doit y avoir une raison à cela. L'utilisation de fonctionnalités Redux dans les composants peut être justifiée si les composants diffèrent par les fonctionnalités suivantes:

  • Ils utilisent les E / S. Par exemple, ils fonctionnent avec un réseau ou avec certains appareils.
  • Ils y enregistrent des données ou en chargent des données.
  • Ils travaillent avec leur état conjointement avec des composants qui ne sont pas leurs descendants.
  • Ils traitent avec toute logique métier avec laquelle les autres parties de l'application traitent, soit - ils traitent les données qui sont utilisées dans d'autres parties de l'application.

Voici un autre exemple tiré de l'application TDDDay :

 import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { compose } from 'ramda'; import page from '../../hocs/page.js'; import Purchase from './purchase-component.js'; import { addHolder, removeHolder, getHolders } from './purchase-reducer.js'; const PurchasePage = () => {  //      // mapStateToProps  mapDispatchToProps  const dispatch = useDispatch();  const holders = useSelector(getHolders); const props = {    //           //    dispatch.    addHolder: compose(      dispatch,      addHolder    ),    removeHolder: compose(      dispatch,      removeHolder    ),    holders,  }; return <Purchase {...props} />; }; // `page` -    ,    //        . export default page(PurchasePage); 

Ce document ne traite pas du DOM. Il s'agit d'un composant de présentation. Il est connecté à Redux à l' aide de l'API react-redux avec prise en charge du hook .

Redux est utilisé ici car nous avons besoin des données que ce formulaire gère pour être utilisées dans d'autres parties de l'interface utilisateur. Et une fois l'opération d'achat terminée, nous devons enregistrer les informations pertinentes dans la base de données.

Les fragments d'état avec lesquels ce code fonctionne sont utilisés par divers composants; ils ne sont pas traités par un seul composant. Ce ne sont pas des données qui n'existent que sur une courte période. Ces données peuvent être considérées comme permanentes, elles peuvent être utilisées sur différents écrans de l'application et en plusieurs sessions. Ce sont tous des scénarios dans lesquels les états du composant pour le stockage des données ne peuvent pas être appliqués. Certes, cela est toujours possible, mais uniquement si le créateur de l'application écrit, sur la base de l'API React, sa propre bibliothèque de gestion de l'état. C'est beaucoup plus difficile à faire que d'utiliser simplement Redux.

L'API React Suspense , à l'avenir, peut être utile lors du stockage de données dans un état et de leur chargement à partir de celui-ci. Nous devons attendre sa sortie et voir s'il peut remplacer les modèles de sauvegarde et de chargement des données Redux. Redux nous permet de séparer clairement les effets secondaires du reste de la logique des composants, alors que nous n'avons pas besoin de travailler avec les services d'E / S d'une manière spéciale. (La raison pour laquelle je préfère la bibliothèque redux-saga au middleware redux-thunk est l'isolation des effets). Afin de concurrencer Redux dans ce scénario, l'API React devra fournir une isolation d'effet.

Redux est l'architecture


Redux est bien plus (et souvent beaucoup moins) qu'une bibliothèque de gestion d'état. Il s'agit également d'un sous-ensemble de l'architecture Flux , qui définit de manière beaucoup plus stricte la manière dont les changements d'état sont mis en œuvre. En savoir plus sur l'architecture Redux ici .

J'utilise souvent des réducteurs créés dans le style Redux dans les cas où j'ai besoin de maintenir l'état complexe du composant, mais je n'ai pas besoin d'utiliser la bibliothèque Redux. J'utilise également des actions créées dans l'esprit de Redux (et même des outils Redux comme Autodux et redux-saga ) pour envoyer des actions aux applications Node.js. Cependant, je n'importe même pas Redux dans de telles applications.

Le projet Redux a toujours été plus une architecture et un ensemble d'accords volontaires qu'une bibliothèque. En fait, l'implémentation de base de Redux peut être présentée littéralement en quelques dizaines de lignes de code.

Cela se révélera être une bonne nouvelle pour ceux qui souhaitent utiliser plus souvent l'état local des composants avec des crochets et ne pas tout lier à Redux.

React prend en charge le crochet useReducer , qui peut fonctionner avec les réducteurs de style Redux. C'est bon pour implémenter une logique non triviale de travail avec l'état, pour travailler avec des fragments d'état dépendants, etc. Si vous rencontrez un problème pour lequel l'état temporaire d'un composant individuel convient, vous pouvez utiliser l'architecture Redux pour travailler avec cet état, mais au lieu de la bibliothèque Redux, vous pouvez utiliser le hook useReducer pour gérer l'état.

Si plus tard, vous devez établir un stockage permanent des données que vous ne stockiez que temporairement, alors vous serez prêt à 90% pour un tel changement. Il vous suffit de connecter le composant au référentiel Redux et d'y ajouter le réducteur correspondant.

Q & A


Le déterminisme est-il rompu si Redux ne gère pas toutes les données d'application?


Non, ce n'est pas cassé. En fait, l'utilisation de Redux ne rend pas un projet déterministe. Mais les accords le sont. Si vous voulez que votre état Redux soit déterministe, utilisez des fonctions pures . La même chose s'applique aux situations dans lesquelles il est nécessaire que l'état temporaire des composants locaux soit déterminé.

▍ La bibliothèque Redux doit-elle jouer le rôle d'une source unique de données fiables?


Le principe d'une source unique de données fiables n'indique pas qu'il est nécessaire que toutes les données incluses dans l'état de l'application soient stockées en un seul endroit. La signification de ce principe est que chaque fragment de l'État ne devrait avoir qu'une seule source de données fiables. En conséquence, nous pouvons avoir de nombreux fragments d'état, chacun ayant sa propre source de données fiables.

Cela signifie que le programmeur peut décider ce qui est transféré à Redux et ce qui est transféré à l'état des composants. Les données déterminant l'état peuvent également provenir d'autres sources. Par exemple, à partir d'une API de navigateur qui vous permet de travailler avec des informations sur l'adresse de la page que vous consultez.

Redux est un excellent outil pour prendre en charge une seule source de données fiables pour l'état d'une application. Mais si l'état du composant est localisé et utilisé exclusivement au sein de ce composant, alors, par définition, cet état possède déjà une source unique de données fiables - l'état du composant React.

Si vous mettez des données dans l'état Redux, vous devez toujours lire ces données dans l'état Redux. Pour tout ce qui se trouve dans le référentiel Redux, ce référentiel doit être la seule source de données fiables.

Mettre tout dans un état Redux, si nécessaire, est parfaitement normal. Cela affectera peut-être les performances si vous utilisez des fragments d'état qui doivent être mis à jour fréquemment, ou si vous parlez de stocker l'état d'un composant dans lequel des fragments d'état dépendants sont largement utilisés. Vous ne devez pas vous soucier des performances tant qu'il n'y a pas de problèmes de performances. Mais si vous êtes préoccupé par le problème de performances, essayez les deux façons de travailler avec l'État et évaluez leur impact sur les performances. Profilez votre projet et souvenez-vous du modèle de performance RAIL.

▍ Dois-je utiliser la fonction de connexion de react-redux, ou est-il préférable d'utiliser des crochets?


Cela dépend de beaucoup. La fonction de connect crée un composant d'ordre supérieur adapté à une utilisation répétée et les crochets sont optimisés pour l'intégration avec un seul composant.

Dois-je connecter les mêmes propriétés à différents composants? Si oui, utilisez connect . Sinon, je préférerais choisir des crochets. Par exemple, imaginez que vous disposez d'un composant chargé d'autoriser les autorisations pour les actions de l'utilisateur:

 import { connect } from 'react-redux'; import RequiresPermission from './requires-permission-component'; import { userHasPermission } from '../../features/user-profile/user-profile-reducer'; import curry from 'lodash/fp/curry'; const requiresPermission = curry(  (NotPermittedComponent, { permission }, PermittedComponent) => {    const mapStateToProps = state => ({      NotPermittedComponent,      PermittedComponent,      isPermitted: userHasPermission(state, permission),    });    return connect(mapStateToProps)(RequiresPermission);  }, ); export default requiresPermission; 

Maintenant, si un administrateur travaille intensivement avec l'application, dont toutes les actions nécessitent une autorisation spéciale, vous pouvez créer un composant d'ordre supérieur qui combine toutes ces autorisations avec toutes les fonctionnalités de bout en bout nécessaires:

 import NextError from 'next/error'; import compose from 'lodash/fp/compose'; import React from 'react'; import requiresPermission from '../requires-permission'; import withFeatures from '../with-features'; import withAuth from '../with-auth'; import withEnv from '../with-env'; import withLoader from '../with-loader'; import withLayout from '../with-layout'; export default compose(  withEnv,  withAuth,  withLoader,  withLayout(),  withFeatures,  requiresPermission(() => <NextError statusCode={404} />, {    permission: 'admin',  }), ); 

Voici comment l'utiliser:

 import compose from 'lodash/fp/compose'; import adminPage from '../HOCs/admin-page'; import AdminIndex from '../features/admin-index/admin-index-component.js'; export default adminPage(AdminIndex); 

L'API de composant d'ordre supérieur est pratique pour cette tâche. Il vous permet de le résoudre plus succinctement, en utilisant moins de code qu'en utilisant des hooks. Mais pour utiliser la fonction connect , vous devez vous rappeler qu'elle prend mapStateToProps comme premier argument et mapStateToProps comme second. Il ne faut pas oublier que cette fonction peut prendre des fonctions ou des littéraux d'objet. Vous devez savoir en quoi les différentes utilisations de connect diffèrent, et qu'il s'agit d'une fonction curry, mais son curry n'est pas effectué automatiquement.

En d'autres termes, je peux dire que je crois que pendant le développement de connect beaucoup de travail a été fait dans le sens de la concision du code, mais le code résultant n'est ni particulièrement lisible, ni particulièrement pratique. Si je n'ai pas besoin de travailler avec plusieurs composants, je préférerai volontiers l'API de connect peu pratique à une API de connect beaucoup plus pratique, même si cela entraînera une augmentation de la quantité de code.

▍ Si un singleton est considéré comme un anti-pattern et que Redux est un singleton, cela signifie-t-il que Redux est un anti-pattern?


Non, non. L'utilisation d'un singleton dans le code fait allusion à la qualité douteuse de ce code, indiquant la présence d'un état mutable partagé en lui. C'est un véritable anti-pattern. Redux, en revanche, empêche la mutation de l'état partagé par encapsulation (vous ne devez pas modifier l'état de l'application directement, en dehors des réducteurs; Redux résout le problème de changement d'état) et en envoyant des messages (seul l'objet d'événement envoyé peut provoquer un changement d'état).

Résumé


Redux remplace-t-il les crochets React? Les crochets sont excellents, mais ils ne remplacent pas Redux.

Nous espérons que ce matériel vous aidera à choisir un modèle de gestion d'état pour vos projets React.

Chers lecteurs! Avez-vous rencontré des situations dans lesquelles les crochets React peuvent remplacer Redux?

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


All Articles