Fermer

juin 5, 2019

Comment remplacer Redux par des crochets React et l'API contextuelle –


Le moyen le plus répandu de gérer l’état d’application partagée dans React consiste à utiliser un cadre tel que Redux. Récemment, l'équipe de React a introduit plusieurs nouvelles fonctionnalités, notamment React Hooks et l'API de contexte. Ces deux fonctionnalités ont en effet éliminé de nombreux problèmes auxquels les développeurs de grands projets React ont été confrontés. L’un des plus gros problèmes était le «forage d’appoint» qui était commun avec les composants imbriqués. La solution consistait à utiliser une bibliothèque de gestion d'état telle que Redux. Malheureusement, cela a entraîné des dépenses d'écriture standardisées, mais il est maintenant possible de remplacer Redux par React Hooks et l'API de contexte.

Dans cet article, vous allez apprendre un nouveau mode de traitement de l'état dans vos projets React sans l’écriture de code excessif ou l’installation de plusieurs bibliothèques, comme c’est le cas avec Redux. Les crochets React vous permettent d'utiliser l'état local à l'intérieur des composants de la fonction, tandis que l'API de contexte vous permet de partager l'état avec d'autres composants.

Conditions préalables

Pour pouvoir suivre ce didacticiel, vous devez disposer de bases solides. dans les sujets suivants:

La technique que vous allez apprendre ici est basée sur des modèles introduits dans Redux. Cela signifie que vous devez bien comprendre les actions des réducteurs et avant de poursuivre. J'utilise actuellement Visual Studio Code qui semble être l'éditeur de code le plus populaire actuellement (en particulier pour les développeurs JavaScript). Si vous êtes sous Windows, je vous recommanderais d'installer Git Bash . Utilisez le terminal Git Bash pour exécuter toutes les commandes fournies dans ce tutoriel. Cmder est également un bon terminal capable d'exécuter la plupart des commandes Linux sous Windows.

Vous pouvez accéder au projet complet utilisé dans ce tutoriel à partir de ce référentiel GitHub .

Nouvelle technique de gestion des états

Les projets React requièrent deux types d’états:

Les états locaux ne peuvent être utilisés que dans les composants créés. Les états globaux peuvent être partagés entre plusieurs composants. En tout état de cause, il existe deux manières de déclarer et de gérer un état à l’aide des crochets React:

useState est recommandé pour le traitement de valeurs simples telles que des nombres ou des chaînes. Cependant, lorsqu'il s'agit de gérer des structures de données complexes, vous devrez utiliser useReducer . Contrairement à useState qui n'est fourni qu'avec une fonction setValue le crochet useReducer vous permet de spécifier autant de fonctions que vous le souhaitez. Par exemple, un état de tableau d'objets nécessitera au moins des fonctions permettant d'ajouter, de mettre à jour et de supprimer un élément.

Une fois que vous avez déclaré votre état à l'aide de useState ou de Réducteur vous pouvez lever Il est possible d'utiliser Global React Context . C'est la technologie qui vous permettra de partager des valeurs entre les composants sans avoir à transmettre des accessoires. Lorsque vous déclarez un objet de contexte, il sert de fournisseur pour que d'autres composants utilisent et souscrivent aux modifications de contexte. Vous pouvez ajouter autant de consommateurs de composants que vous le souhaitez au fournisseur. L'état partagé sera automatiquement synchronisé avec tous les composants souscrits.

Commençons par créer le projet afin d'avoir une connaissance pratique de son fonctionnement.

Configuration du projet

Le moyen le plus simple de créer un projet consiste à utiliser create-react-app outil. Cependant, l'outil installe une tonne de dépendances de développement qui consomment beaucoup d'espace disque. De ce fait, l'installation et le démarrage du serveur dev sont plus longs. Si les problèmes mineurs ne vous gênent pas, vous pouvez créer un nouveau projet React avec l’outil. Vous pouvez l'appeler réagir-hooks-context-demo .

Une autre façon de créer un nouveau projet React consiste à cloner un projet de démarrage configuré pour utiliser le Parcel JS en tant que constructeur. Cette méthode consomme au moins 50% moins d'espace disque et démarre le serveur de développement plus rapidement que l'outil create-react-app . J’en ai créé un spécialement pour les didacticiels React tels que celui-ci. Je vous recommande de commencer par créer un référentiel complètement vide GitHub sur votre compte avant de suivre les instructions suivantes:

 $ git clone git@github.com: brandiqa / react-parcel-starter.git réagir-crochets-contexte-démo
$ cd react-hooks-context-demo
$ git remote rm origin
# Remplacez `username` et` repositoryName` par le vôtre
$ git à distance ajouter l'origine git@github.com: nom d'utilisateur / repositoryName.git
$ git config master.remote origin
$ git config master.merge refs / heads / master
$ git push -u origine master
# Installer les dépendances
$ npm install

Une fois que vous avez exécuté toutes les instructions ci-dessus, vous pouvez utiliser la commande npm start pour démarrer le serveur de développement. Vous devrez lancer votre navigateur et naviguer jusqu'à la page localhost: 1234 .

 01-react-parcel-starter

Si vous avez utilisé le créer-réagir-app outil, il sera bien sûr différent. Cela n’est pas grave, car nous allons modifier la vue par défaut à l’étape suivante. Si votre projet a bien démarré, vous pouvez passer à la section suivante.

Installation d'une bibliothèque d'interface utilisateur

Cette étape n'est pas nécessaire pour cette rubrique. Cependant, j'aime toujours construire des interfaces propres et belles avec un minimum d'effort. Pour ce tutoriel, nous allons utiliser Semantic UI React . Comme il s’agit d’un tutoriel sur la gestion des états, je n’expliquerai pas le fonctionnement de la bibliothèque. Je vais seulement vous montrer comment l'utiliser.

 npm installe sémantique-ui-réact sémantique-ui-css

Ouvrez index.js et insérez les importations suivantes:

 import 'semantic-ui-css / semantic.min.css';
import './index.css';

C’est tout ce dont nous avons besoin pour que notre projet commence à utiliser l’interface utilisateur sémantique. Commençons par le premier exemple illustrant cette nouvelle technique de gestion d’états.

Exemple de compteur

Dans cet exemple, nous allons créer une simple démo de compteur composée de deux boutons et d’un bouton d’affichage. Afin de démontrer l'état global, cet exemple sera constitué de deux composants de présentation. Premièrement, nous devrons définir notre objet de contexte où l’état vivra. Il est similaire au magasin de Redux. La création de notre code de contexte à utiliser à cette fin nécessitera un peu de code passe-partout qui devra être dupliqué dans chaque projet. Heureusement, quelqu'un a déjà écrit pour cela un hook personnalisé qui vous permettra de créer votre objet de contexte sur une seule ligne. Installez simplement le paquet constaté :

 npm install constat

Une fois installé, vous devriez pouvoir continuer. J'ai placé des commentaires dans le code pour expliquer ce qui se passe. Créez le fichier d'objet de contexte de magasin context / CounterContext.js et insérez le code suivant:

 import {useState} à partir de "react";
importer createUseContext de "constat"; // Créateur d'objet de contexte d'état

// Étape 1: Créez un hook personnalisé contenant votre état et vos actions
function useCounter () {
  const [count, setCount] = useState (0);
  const increment = () => setCount (prevCount => prevCount + 1);
  const decrement = () => setCount (prevCount => prevCount - 1);
  return {count, increment, decrement};
}

// Étape 2: Déclarez votre objet d'état de contexte pour partager l'état avec d'autres composants
export const useCounterContext = createUseContext (useCounter);

Créez le composant parent views / Counter.jsx et insérez ce code:

 import React from "react";
importer {Segment} de "semantic-ui-react";

importer CounterDisplay de "../components/CounterDisplay";
importer des Contre-Boutons de "../components/CounterButtons";
import {useCounterContext} from "../context/CounterContext";

fonction d'exportation par défaut Counter () {
  revenir (
    // étape 3: encapsulez les composants que vous souhaitez partager avec le fournisseur de contexte
    
      

Counter

); }

Créez le composant de présentation components / CounterDisplay.jsx et insérez le code suivant:

 import React from "react";
importer {statistique} de "semantic-ui-react";
import {useCounterContext} from "../context/CounterContext";

fonction d'exportation par défaut CounterDisplay () {
  // Étape 4: Consommez le contexte pour accéder à l'état partagé
  const {count} = useCounterContext ();
  revenir (
    
       {count} 
       Counter 
    
  );
}

Créez le composant de présentation components / CounterButtons.jsx et insérez ce code:

 import React from "react";
importer {Button} de "semantic-ui-react";
import {useCounterContext} from "../context/CounterContext";

fonction d'exportation par défaut CounterButtons () {
  // Étape 4: Consumez le contexte pour accéder aux actions partagées
  const {increment, decrement} = useCounterContext ();
  revenir (
    
); }

Remplacez le code dans App.jsx par ceci:

 import Réagissez à partir de "react";
importer {conteneur} de "semantic-ui-react";

importer un compteur à partir de "./views/Counter";

fonction d'exportation par défaut App () {
  revenir (
    
      

Démo contextuelle de Reag Hooks

); }

La page de votre navigateur devrait avoir la vue suivante. Cliquez sur les boutons pour vous assurer que tout fonctionne correctement:

 02-counter-demo .

J'espère que cet exemple a du sens – lisez les commentaires que j'ai inclus. Passons à la section suivante où nous allons créer un exemple un peu plus avancé.

Dans cet exemple, nous allons créer une page CRUD de base pour la gestion des contacts. Il sera composé de deux composants de présentation et d’un conteneur. Il y aura également un objet de contexte pour la gestion de l'état des contacts. Comme notre arbre d'état sera un peu plus complexe que l'exemple précédent, nous devrons utiliser le crochet useReducer .

Créer l'objet de contexte d'état context / ContactContext.js et insérez le code suivant:

 import {useReducer} de "react";
importer _ de "lodash";
importer createUseContext de "constat";

// Définir l'état initial de notre application
const initialState = {
  contacts: [
    {
      id: "098",
      name: "Diana Prince",
      email: "diana@us.army.mil"
    },
    {
      id: "099",
      name: "Bruce Wayne",
      email: "bruce@batmail.com"
    },
    {
      id: "100",
      name: "Clark Kent",
      email: "clark@metropolitan.com"
    }
  ],
  chargement: faux,
  erreur: null
};

// Définir un réducteur de fonction pur
const réducteur = (état, action) => {
  commutateur (action.type) {
    cas "ADD_CONTACT":
      revenir {
        contacts: [...state.contacts, action.payload]
      };
    cas "DEL_CONTACT":
      revenir {
        contacts: state.contacts.filter (contact => contact.id! = action.payload)
      };
    cas "START":
      revenir {
        chargement: vrai
      };
    cas "COMPLETE":
      revenir {
        chargement: faux
      };
    défaut:
      jeter une nouvelle erreur ();
  }
};

// Définit votre hook personnalisé contenant votre état, votre répartiteur et vos actions
const useContacts = () => {
  const [state, dispatch] = useReducer (réducteur, initialState);
  const {contacts, chargement} = state;
  const addContact = (nom, email) => {
    envoi({
      type: "ADD_CONTACT",
      charge utile: {id: _.uniqueId (10), nom, email}
    });
  };
  const delContact = id => {
    envoi({
      type: "DEL_CONTACT",
      charge utile: id
    });
  };
  retourne {contacts, chargement, addContact, delContact};
};

// Partagez votre crochet personnalisé
export const useContactsContext = createUseContext (useContacts);

Créez le composant parent views / Contacts.jsx et insérez ce code:

 import React from "react";
importer {Segment, en-tête} de "semantic-ui-react";
importer ContactForm depuis "../components/ContactForm";
import ContactTable de "../components/ContactTable";
import {useContactsContext} from "../context/ContactContext";

fonction d'exportation par défaut Contacts () {
  revenir (
    // Enveloppez les composants que vous souhaitez partager votre état de hook personnalisé
    
      
        
Contacts
); }

Créez le composant de présentation components / ContactTable.jsx et insérez le code suivant:

 import React, {useState} à partir de "react";
importer {Segment, Table, Bouton, Icône} de "semantic-ui-react";
import {useContactsContext} from "../context/ContactContext";

fonction d'exportation par défaut ContactTable () {
  // S'abonner à l'état 'contacts` et accéder à l'action `delContact`
  const {contacts, delContact} = useContactsContext ();
  // Déclarer un état local à utiliser en interne par ce composant
  const [selectedId, setSelectedId] = useState ();

  const onRemoveUser = () => {
    delContact (selectedId);
    setSelectedId (null); // Effacer la sélection
  };

  const rows = contacts.map (contact => (
     setSelectedId (contact.id)}
      active = {contact.id === selectedId}
    >
       {contact.id} 
       {contact.name} 
       {contact.email} 
    
  ));

  revenir (
    
      
          
             Id 
             Nom 
             E-mail 
          
         {rows} 
          
            
            
              
            
          
        
); }

Créez le composant de présentation components / ContactForm.jsx et insérez le code suivant:

 import React, {useState} à partir de "react";
importer {Segment, Formulaire, Entrée, Bouton} de "semantic-ui-react";
import {useContactsContext} from "../context/ContactContext";

fonction par défaut d'exportation ContactForm () {
  nom de const = useFormInput ("");
  const email = useFormInput ("");
  // Consume le magasin de contexte pour accéder à l'action `addContact`
  const {addContact} = useContactsContext ();

  const onSubmit = () => {
    addContact (name.value, email.value);
    // Réinitialiser le formulaire
    name.onReset ();
    email.onReset ();
  };

  revenir (
    
      
); } function useFormInput (initialValue) {   const [value, setValue] = useState (initialValue);   fonction handleChange (e) {     setValue (e.target.value);   }   function handleReset () {     setValue ("");   }   revenir {     valeur,     onChange: handleChange,     onReset: handleReset   }; }

Insérer le code suivant dans App.jsx en conséquence:

 importer des contacts depuis "./views/Contacts";
// ...

  

Démonstration du contexte des crochets à réaction

  {/ * * /}   
;

Une fois le code implémenté, la page de votre navigateur doit être actualisée. Pour supprimer un contact, vous devez d'abord sélectionner une ligne, puis appuyer sur le bouton "Supprimer". Pour créer un nouveau contact, remplissez simplement le formulaire et cliquez sur le bouton "Nouveau contact".

 03-contacts-example

Passez en revue le code pour vous assurer de tout comprendre. Lisez les commentaires que j'ai inclus dans le code.

Résumé

J'espère que ces deux exemples fournissent une excellente compréhension de la façon dont vous pouvez gérer un état d'application partagée sans Redux. Si vous aviez réécrit ces exemples sans crochets ni API de contexte, cela aurait généré beaucoup plus de code. Vous devez uniquement utiliser l'API de contexte, le cas échéant. Les accessoires auraient dû être utilisés dans ces exemples s'il ne s'agissait pas d'un didacticiel.

Vous avez peut-être remarqué dans le deuxième exemple qu'il existe quelques variables d'état non utilisées, à savoir loading et error . En tant que défi, vous pouvez continuer à faire évoluer cette application pour les utiliser. Par exemple, vous pouvez implémenter un faux délai et faire en sorte que les composants de présentation affichent un statut de chargement. Vous pouvez également aller beaucoup plus loin et accéder à une véritable API distante. C’est là que la variable d’état error peut être utile pour afficher les messages d’erreur.

La seule question que vous voudrez peut-être vous poser maintenant: Redux est-il nécessaire pour les projets futurs? L’un des inconvénients de cette technique est que vous ne pouvez pas utiliser le Redux DevTool Addon pour déboguer l’état de votre application. Cependant, cela pourrait changer à l'avenir avec le développement d'un nouvel outil. Évidemment, en tant que développeur, vous aurez toujours besoin d'apprendre Redux pour gérer les projets existants. Si vous démarrez un nouveau projet, vous devrez vous demander, à vous et à votre équipe, s'il est vraiment nécessaire d'utiliser une bibliothèque de gestion d'état.




Source link