Fermer

février 1, 2024

Maîtriser les Hooks React : un voyage au-delà de useState et useEffect

Maîtriser les Hooks React : un voyage au-delà de useState et useEffect


Introduction

Dans le domaine du développement React, une gestion efficace des états est cruciale pour créer des applications évolutives et performantes. Tandis que le familier utiliserÉtat et utiliserEffet Les hooks sont des outils puissants pour gérer l’état des composants et gérer les effets secondaires, notre voyage vers les hooks React ne s’arrête pas là. Cet article de blog se penchera sur les hooks React avancés, explorant comment ils améliorent la gestion de l’état et optimisent les performances dans les applications complexes.

Section 1 : Récapitulatif des bases

Avant de nous lancer dans notre voyage vers les hooks React avancés, prenons un moment pour revoir les bases. Un bref récapitulatif de utiliserÉtat et utiliserEffet fournira une base solide à ceux qui ont besoin d’une remise à niveau.

  • utiliserÉtat – Une différence clé entre les composants de classe et les composants fonctionnels réside dans le fait que les composants de classe ont un état tandis que les composants fonctionnels sont sans état. Le hook useState nous permet d’ajouter un état local à un composant fonctionnel. Ce crochet conserve un état entre les rendus.

Par exemple-

importer React, {useState} depuis ‘react’ ;

function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}


  • utiliserEffet – Le hook useEffect nous permet d’implémenter des méthodes de cycle de vie pour indiquer au composant d’effectuer un « effet » après son rendu. Les différents types d’effets sont illimités, comme la modification de l’image d’arrière-plan ou du titre du document, l’ajout d’animations ou de musique, la récupération de données et les abonnements.

Par exemple-

import React, { useState, useEffect } from 'react';

function Example() {
const [count, setCount] = useState(0);

// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

Maintenant que nous avons revu les bases avec useState et useEffect, passons au niveau suivant en examinant les hooks React avancés. Rejoignez-nous pour explorer de puissantes techniques de gestion d’état qui peuvent améliorer considérablement le développement d’applications robustes et réactives.

Section 2 : La nécessité d’une gestion avancée de l’état

Les développeurs sont souvent aux prises avec une logique d’état complexe à mesure que les applications React gagnent en complexité. Cette section abordera les défis qui se posent et soulignera l’importance croissante de l’optimisation des performances pour des expériences utilisateur fluides.

Voici quelques exemples qui mettent en évidence la nécessité de techniques avancées de gestion d’état :

  • Hiérarchies des composants et perçage des accessoires :

Défi: Dans une grande application avec des composants profondément imbriqués, transmettre l’état à travers plusieurs niveaux (perçage d’accessoires) devient fastidieux et conduit à un code moins maintenable.
Solution: Les hooks avancés comme useContext peuvent aider à gérer l’état global, réduisant ainsi le besoin de transmettre des accessoires via chaque composant intermédiaire.

  • Plusieurs composants en fonction du même état :

Défi: Lorsque plusieurs composants dispersés dans l’application doivent accéder au même élément d’état, gérer et mettre à jour cet état de manière à garantir la cohérence devient un défi.
Solution: utiliserRéducteur peut centraliser la logique d’état, permettant à plusieurs composants d’interagir avec le même état via des actions distribuées.

  • Formulaires complexes et validation :

Défi: La gestion de formulaires complexes comportant plusieurs champs, des règles de validation et un rendu conditionnel basé sur l’état du formulaire peut conduire à un code alambiqué.
Solution: utiliserRéducteur peut simplifier la gestion de l’état du formulaire, et utiliserEffet peut être utilisé pour gérer la validation asynchrone ou les effets secondaires liés à la soumission du formulaire.

  • Mises à jour et synchronisation en temps réel :

Défi: La création de fonctionnalités nécessitant des mises à jour en temps réel, telles que l’édition collaborative ou le chat en direct, implique de gérer les changements d’état sur plusieurs clients et d’assurer la synchronisation.
Solution: Les hooks avancés peuvent être utilisés avec des technologies telles que WebSockets pour gérer efficacement les mises à jour d’état en temps réel.

  • Optimisation des rendus pour les grands ensembles de données :

Défi: L’affichage de grands ensembles de données dans des composants, où la mise à jour d’un élément ne devrait pas déclencher un nouveau rendu de la liste entière, nécessite une gestion minutieuse de l’état.
Solution: utiliser Mémo et utiliserCallback peut être utilisé pour optimiser les performances en mémorisant les calculs et en évitant les nouveaux rendus inutiles.

  • Interface utilisateur dynamique et indicateurs de fonctionnalités :

Défi: La création d’interfaces utilisateur dynamiques qui s’adaptent aux rôles des utilisateurs, aux autorisations ou aux indicateurs de fonctionnalités introduit des complexités dans la gestion du rendu conditionnel basé sur l’état dynamique.
Solution: Les techniques avancées de gestion d’état peuvent aider à gérer les modifications dynamiques de l’interface utilisateur sans encombrer les composants avec une logique conditionnelle.

  • Support hors ligne et persistance des données :

Défi: Garantir des transitions transparentes entre les modes en ligne et hors ligne, conserver les données localement et synchroniser les modifications avec le serveur posent des défis en matière de gestion de l’état.
Solution: utiliserEffet et des bibliothèques de persistance d’état peuvent être utilisées pour gérer la transition entre les états en ligne et hors ligne.

  • Opérations asynchrones et états de chargement:

Défi: Gérer les opérations asynchrones, telles que les appels d’API, et gérer les états de chargement tout en évitant les nouveaux rendus inutiles peut s’avérer complexe.
Solution: Crochets avancés comme utiliserRéducteur combiné avec utiliserEffet peut rationaliser la gestion de l’état asynchrone et les indicateurs de chargement.

Section 3 : Exploration des hooks React avancés

  • utiliserRéducteur : Pierre angulaire de la gestion étatique avancée, utiliserRéducteur offre un changement de paradigme dans la gestion de la logique d’état complexe. Nous explorerons ses concepts et présenterons des exemples concrets illustrant des scénarios dans lesquels utiliserRéducteur brille.

Prenons un scénario dans lequel le panier a une logique complexe, notamment l’ajout d’articles, la suppression d’articles et l’ajustement des quantités. Nous voulons nous assurer que la gestion de l’état reste organisée et facile à étendre à mesure que l’application se développe.

Voici un exemple utilisant utiliserRéducteur:

import React, { useReducer } from 'react';

// Action types
const ADD_TO_CART = 'ADD_TO_CART';
const REMOVE_FROM_CART = 'REMOVE_FROM_CART';
const ADJUST_QUANTITY = 'ADJUST_QUANTITY';

// Reducer function
const cartReducer = (state, action) => {
switch (action.type) {
case ADD_TO_CART:
return {
...state,
cartItems: [...state.cartItems, action.payload],
};
case REMOVE_FROM_CART:
return {
...state,
cartItems: state.cartItems.filter(item => item.id !== action.payload),
};
case ADJUST_QUANTITY:
return {
...state,
cartItems: state.cartItems.map(item =>
item.id === action.payload.id ? { ...item, quantity: action.payload.quantity } : item
),
};
default:
return state;
}
};

// Initial state
const initialState = {
cartItems: [],
};

// Component using useReducer for cart state management
const ShoppingCart = () => {
const [cartState, dispatch] = useReducer(cartReducer, initialState);

// Action creators
const addToCart = (item) => {
dispatch({ type: ADD_TO_CART, payload: item });
};

const removeFromCart = (itemId) => {
dispatch({ type: REMOVE_FROM_CART, payload: itemId });
};

const adjustQuantity = (itemId, quantity) => {
dispatch({ type: ADJUST_QUANTITY, payload: { id: itemId, quantity } });
};

return (
<div>
<h2>Shopping Cart</h2>
<ul>
{cartState.cartItems.map((item) => (
<li key={item.id}>
{item.name} - Quantity: {item.quantity}
<button onClick={() => adjustQuantity(item.id, item.quantity + 1)}>+</button>
<button onClick={() => adjustQuantity(item.id, item.quantity - 1)}>-</button>
<button onClick={() => removeFromCart(item.id)}>Remove</button>
</li>
))}
</ul>
{/* Component for adding items to the cart */}
{/* ... */}
</div>
);
};

export default ShoppingCart;

En utilisant utiliserRéducteur, nous avons encapsulé la logique liée à l’état du panier, ce qui facilite sa gestion et son extension à mesure que les exigences relatives au panier évoluent. Cet exemple montre comment utiliserRéducteur est un outil puissant pour gérer une logique d’état complexe dans des scénarios du monde réel.

  • utiliserContexte : Présentation de useContext, un outil puissant pour gérer l’état global et éliminer le besoin de forage d’accessoires. Découvrez comment il simplifie la propagation des états entre des composants profondément imbriqués, favorisant ainsi un code plus propre et plus maintenable.

Considérez un scénario dans lequel vous souhaitez implémenter une fonctionnalité de changement de thème dans votre application et souhaitez que le thème soit accessible aux composants profondément imbriqués sans le passer par chaque niveau intermédiaire.

Voici un exemple utilisant utiliserContext pour gérer l’état global du thème :

import React, { createContext, useContext, useState } from 'react';

// Create a context for the theme
const ThemeContext = createContext();

// Theme provider component
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');

const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};

// Component using useContext to access the theme
const ThemedComponent = () => {
const { theme, toggleTheme } = useContext(ThemeContext);

return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#333' : '#fff' }}>
<h2>Themed Component</h2>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};

// Another nested component
const NestedComponent = () => {
return (
<div>
<h3>Nested Component</h3>
<ThemedComponent />
</div>
);
};

// App component that uses the ThemeProvider
const App = () => {
return (
<ThemeProvider>
<div>
<h1>Theme Switching App</h1>
<ThemedComponent />
<NestedComponent />
</div>
</ThemeProvider>
);
};

export default App;

By using useContext, the global theme state is easily accessible to any component within the ThemeProvider without the need for prop drilling. This results in cleaner and more maintainable code, especially in applications with deeply nested component hierarchies.
  • utiliserRappel : L’optimisation des performances devient primordiale à mesure que les applications évoluent. Entrez useCallback, un hook pour mémoriser les fonctions et éviter les nouveaux rendus inutiles. Nous discuterons de ses applications et présenterons des scénarios dans lesquels cela change la donne.

Considérez un scénario dans lequel vous disposez d’une liste d’éléments et cliquer sur un élément devrait déclencher une action. Sans mémorisation, une nouvelle référence de fonction est créée à chaque nouveau rendu du composant, ce qui peut entraîner des rendus inutiles pour les composants enfants.

Voici un exemple utilisant utiliserCallback pour optimiser les performances :

import React, { useState, useCallback } from 'react';

// Component that displays a list of items
const ItemList = ({ items, onItemClick }) => {
console.log('ItemList rendered'); // Log when the component renders for demonstration purposes

return (
<ul>
{items.map((item, index) => (
<li key={index} onClick={() => onItemClick(item)}>
{item.name}
</li>
))}
</ul>
);
};

// Parent component that manages the list of items
const ItemListContainer = () => {
const [items, setItems] = useState([
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
]);

// Without useCallback, a new function is created on each render
// const handleItemClick = (item) => {
// console.log(`Item clicked: ${item.name}`);
// };
// With useCallback, the function is memoized and remains the same across renders
const handleItemClick = useCallback((item) => {
console.log(`Item clicked: ${item.name}`);
}, []); // Empty dependency array means the callback doesn't depend on any external variables

return (
<div>
<h2>Item List Container</h2>
<ItemList items={items} onItemClick={handleItemClick} />
</div>
);
};

Exporter le ItemListContainer par défaut ;

Dans les scénarios où les composants dépendent de références de fonctions stables, utiliserCallback change la donne en évitant les nouveaux rendus inutiles et en optimisant les performances de l’application.

Section 4 : Exemples pratiques

Les connaissances théoriques prennent vie avec des exemples pratiques. Cette section fournira des scénarios réels, démontrant comment les hooks React avancés améliorent la lisibilité du code, la maintenabilité et les performances globales des applications.

  • Édition collaborative en temps réel

Scénario: Créer une fonctionnalité d’édition collaborative en temps réel, telle que Google Docs, implique de gérer les changements d’état sur plusieurs clients et d’assurer la synchronisation.
Solution: Utilisez des hooks avancés en conjonction avec des technologies telles que WebSockets pour gérer efficacement les mises à jour d’état en temps réel. utiliserRéducteur peut centraliser la logique d’édition collaborative, garantissant des mises à jour cohérentes et synchronisées.

  • Interface utilisateur dynamique et indicateurs de fonctionnalités

Scénario: La création d’interfaces utilisateur dynamiques qui s’adaptent aux rôles des utilisateurs, aux autorisations ou aux indicateurs de fonctionnalités introduit des complexités dans la gestion du rendu conditionnel basé sur l’état dynamique.
Solution: Utiliser des techniques avancées de gestion de l’État. utiliserContext peut aider à gérer les modifications dynamiques de l’interface utilisateur sans encombrer les composants avec une logique conditionnelle, améliorant ainsi la lisibilité et la maintenabilité du code.

  • Support hors ligne et persistance des données

Scénario: Garantir des transitions transparentes entre les modes en ligne et hors ligne, conserver les données localement et synchroniser les modifications avec le serveur posent des défis en matière de gestion de l’état.
Solution: Utiliser utiliserEffet et des bibliothèques de persistance d’état pour gérer la transition entre les états en ligne et hors ligne. Cela garantit la cohérence des données et améliore les performances globales des applications.

  • Opérations asynchrones et états de chargement

Scénario: Gérer les opérations asynchrones, telles que les appels d’API, et gérer les états de chargement tout en évitant les nouveaux rendus inutiles peut s’avérer complexe.
Solution: Tirez parti des crochets avancés comme utiliserRéducteur combiné avec utiliserEffet pour rationaliser la gestion des états asynchrones et les indicateurs de chargement. Cela améliore la lisibilité du code et optimise les performances.

  • Optimisation des rendus pour les grands ensembles de données

Scénario: L’affichage de grands ensembles de données dans des composants, où la mise à jour d’un élément ne devrait pas déclencher un nouveau rendu de la liste entière, nécessite une gestion minutieuse de l’état.
Solution: Mettre en œuvre utiliser Mémo et utiliserCallback pour optimiser les performances en mémorisant les calculs et en évitant les nouveaux rendus inutiles. Cela garantit une expérience utilisateur fluide avec de grands ensembles de données.

Ces scénarios réels présentent l’application pratique des hooks React avancés pour relever des défis complexes et améliorer différents aspects du développement d’applications.

Les références

https://dev.to/hey_yogini/usereducer-instead-of-usestate-while-calling-apis-3e1l

Voir sur Medium.com

https://legacy.reactjs.org/docs/hooks-effect.html






Source link