Maison > interface Web > js tutoriel > useReducer et en quoi il est différent de useState

useReducer et en quoi il est différent de useState

Susan Sarandon
Libérer: 2024-10-30 20:04:30
original
713 Les gens l'ont consulté

useReducer and how it is different from useState

Table des matières

  1. Présentation
  2. Quand utiliser useState
  3. Quand utiliser useReducer
  4. Exemple 1 : Counter App avec useState
  5. Exemple 2 : Counter App avec useReducer
  6. Exemple 3 : Gestion des entrées de formulaire avec useReducer
  7. Exemple 4 : Créer une application de quiz avec useReducer
  8. Comparaison entre useState et useReducer
  9. Conclusion

Introduction

React propose deux hooks clés pour gérer l'état : useState et useReducer. Bien que les deux soient conçus pour gérer l’état des composants fonctionnels, ils sont utilisés dans différents scénarios. Cet article explore les différences entre les deux et souligne quand vous devez utiliser chacun, avec des exemples pour une meilleure compréhension

Quand utiliser useState

useState est un hook simple et efficace pour gérer l'état local lorsque :

  • Vous avez un état simple à gérer (comme des booléens, des nombres ou des chaînes).
  • Vous souhaitez que les mises à jour directes soient effectuées avec une configuration minimale.
  • L'État n'a pas de transitions ou de dépendances complexes sur plusieurs variables.

Syntaxe de base

const [state, setState] = useState(initialState);
Copier après la connexion
Copier après la connexion
  • état : l'état actuel.
  • setState : Une fonction pour mettre à jour l'état.
  • initialState : L'état initial

Quand utiliser useReducer

useReducer est utile lorsque :

  • Vous avez une logique d'état complexe.
  • Plusieurs mises à jour d'état dépendent les unes des autres.

Syntaxe de base

const [state, dispatch] = useReducer(reducer, initialState);

Copier après la connexion
Copier après la connexion
  • état : l'état actuel.
  • dispatch : Une fonction pour envoyer une action au réducteur pour déclencher une mise à jour de l'état.
  • réducteur : Un réducteur est une fonction pure qui prend deux arguments : l'état actuel et une action. Il renvoie le nouvel état en fonction de l'action.

Syntaxe de base

const reducer = (state, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { count: state.count + 1 };
        case 'DECREMENT':
            return { count: state.count - 1 };
        default:
            return state;
    }
}
Copier après la connexion
Copier après la connexion
  • Action : une action est un objet qui décrit le changement qui devrait se produire
    Il a généralement une propriété type et éventuellement une payload.
    Le type indique au réducteur quel type de changement d'état effectuer.
    La charge utile contient toutes les données supplémentaires nécessaires au changement.

  • InitialState : l'état initial, tout comme initialstate dans useState.

Exemple 1 : application de compteur avec useState

const [state, setState] = useState(initialState);
Copier après la connexion
Copier après la connexion

Explication

  • Nous utilisons useState pour suivre la valeur du nombre.
  • Nous avons deux boutons : un pour incrémenter et un pour décrémenter l'état du décompte.
  • L'état est mis à jour directement à l'aide de la fonction setCount.

Exemple 2 : Counter App avec useReducer

const [state, dispatch] = useReducer(reducer, initialState);

Copier après la connexion
Copier après la connexion

Explication

  • La fonction de réduction contrôle la façon dont l'état doit changer en fonction de l'action envoyée.
  • Au lieu de définir directement l'état, nous envoyons des actions (incrémentation, décrémentation) pour déclencher des changements.

Exemple 3 : Gestion des entrées de formulaire avec useReducer

Élargissons le concept à la gestion d'un formulaire avec plusieurs champs de saisie. Ce scénario est idéal pour useReducer car il met à jour plusieurs propriétés d'état en fonction des actions.

const reducer = (state, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { count: state.count + 1 };
        case 'DECREMENT':
            return { count: state.count - 1 };
        default:
            return state;
    }
}
Copier après la connexion
Copier après la connexion

Explication

  • Le réducteur gère l'état du formulaire en mettant à jour différentes propriétés (nom, email) en fonction du type d'action.
  • Dispatch envoie l'action au réducteur pour mettre à jour l'état. La charge utile transporte les données (par exemple, la valeur d'entrée).

Exemple 4 : Créer une application de quiz avec useReducer

Remarque : le style a été réalisé avec tailwindcss

import React, { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(count - 1)}>Decrement</button>
    </div>
  );
}


Copier après la connexion

Explication

*état initial avec useReducer

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

export default function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

Copier après la connexion
  • Fonction réducteur
import React, { useReducer } from 'react';

const initialState = {
  name: '',
  email: ''
};

function reducer(state, action) {
  switch (action.type) {
    case 'setName':
      return { ...state, name: action.payload };
    case 'setEmail':
      return { ...state, email: action.payload };
    default:
      return state;
  }
}

export default function Form() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <input
        type="text"
        value={state.name}
        onChange={(e) => dispatch({ type: 'setName', payload: e.target.value })}
        placeholder="Name"
      />
      <input
        type="email"
        value={state.email}
        onChange={(e) => dispatch({ type: 'setEmail', payload: e.target.value })}
        placeholder="Email"
      />
      <p>Name: {state.name}</p>
      <p>Email: {state.email}</p>
    </div>
  );
}




Copier après la connexion

Le réducteur gère trois actions :

  • SELECT_OPTION : lorsque l'utilisateur sélectionne une réponse
  • NEXT_QUESTION : Lorsque vous passez à la question suivante
  • RESTART : Au redémarrage du quiz

Logique de style

import React, { useReducer } from 'react';

// Quiz data with detailed explanations
const quizData = [
  {
    question: "What hook is used to handle complex state logic in React?",
    options: ["useState", "useReducer", "useEffect", "useContext"],
    correct: 1,
    explanation: "useReducer is specifically designed for complex state management scenarios."
  },
  {
    question: "Which function updates the state in useReducer?",
    options: ["setState", "dispatch", "update", "setReducer"],
    correct: 1,
    explanation: "dispatch is the function provided by useReducer to trigger state updates."
  },
  {
    question: "What pattern is useReducer based on?",
    options: ["Observer Pattern", "Redux Pattern", "Factory Pattern", "Module Pattern"],
    correct: 1,
    explanation: "useReducer is inspired by Redux's state management pattern."
  }
];

// Initial state with feedback state added
const initialState = {
  currentQuestion: 0,
  score: 0,
  showScore: false,
  selectedOption: null,
  showFeedback: false, // New state for showing answer feedback
};

// Enhanced reducer with feedback handling
const reducer = (state, action) => {
  switch (action.type) {
    case 'SELECT_OPTION':
      return {
        ...state,
        selectedOption: action.payload,
        showFeedback: true, // Show feedback when option is selected
      };
    case 'NEXT_QUESTION':
      const isCorrect = action.payload === quizData[state.currentQuestion].correct;
      const nextQuestion = state.currentQuestion + 1;
      return {
        ...state,
        score: isCorrect ? state.score + 1 : state.score,
        currentQuestion: nextQuestion,
        showScore: nextQuestion === quizData.length,
        selectedOption: null,
        showFeedback: false, // Reset feedback for next question
      };
    case 'RESTART':
      return initialState;
    default:
      return state;
  }
};

const Quiz = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const { currentQuestion, score, showScore, selectedOption, showFeedback } = state;

  const handleOptionClick = (optionIndex) => {
    dispatch({ type: 'SELECT_OPTION', payload: optionIndex });
  };

  const handleNext = () => {
    if (selectedOption !== null) {
      dispatch({ type: 'NEXT_QUESTION', payload: selectedOption });
    }
  };

  const handleRestart = () => {
    dispatch({ type: 'RESTART' });
  };

  if (showScore) {
    return (
      <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
        <div className="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
          <h2 className="text-2xl font-bold text-center mb-4">Quiz Complete!</h2>
          <p className="text-xl text-center mb-6">
            Your score: {score} out of {quizData.length}
          </p>
          <button
            onClick={handleRestart}
            className="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600 transition-colors"
          >
            Restart Quiz
          </button>
        </div>
      </div>
    );
  }

  const currentQuizData = quizData[currentQuestion];
  const isCorrectAnswer = (optionIndex) => optionIndex === currentQuizData.correct;

  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 p-4">
      <div className="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
        <div className="mb-6">
          <p className="text-sm text-gray-500 mb-2">
            Question {currentQuestion + 1}/{quizData.length}
          </p>
          <h2 className="text-xl font-semibold mb-4">{currentQuizData.question}</h2>
        </div>

        <div className="space-y-3 mb-6">
          {currentQuizData.options.map((option, index) => {
            let buttonStyle = 'bg-gray-50 hover:bg-gray-100';

            if (showFeedback && selectedOption === index) {
              buttonStyle = isCorrectAnswer(index) 
                ? 'bg-green-100 border-2 border-green-500 text-green-700'
                : 'bg-red-100 border-2 border-red-500 text-red-700';
            }

            return (
              <button
                key={index}
                onClick={() => handleOptionClick(index)}
                disabled={showFeedback}
                className={`w-full p-3 text-left rounded-lg transition-colors ${buttonStyle}`}
              >
                {option}
              </button>
            );
          })}
        </div>

        {showFeedback && (
          <div className={`p-4 rounded-lg mb-4 ${
            isCorrectAnswer(selectedOption)
              ? 'bg-green-50 text-green-800'
              : 'bg-red-50 text-red-800'
          }`}>
            {isCorrectAnswer(selectedOption)
              ? "Correct! "
              : `Incorrect. The correct answer was: ${currentQuizData.options[currentQuizData.correct]}. `}
            {currentQuizData.explanation}
          </div>
        )}

        <button
          onClick={handleNext}
          disabled={!showFeedback}
          className={`w-full py-2 px-4 rounded transition-colors ${
            !showFeedback
              ? 'bg-gray-300 cursor-not-allowed'
              : 'bg-blue-500 text-white hover:bg-blue-600'
          }`}
        >
          Next Question
        </button>
      </div>
    </div>
  );
};

export default Quiz;


Copier après la connexion

Ce code détermine le style du bouton :

  • Par défaut : fond gris
  • Bonne réponse : Fond vert avec bordure verte
  • Mauvaise réponse : Fond rouge avec bordure rouge

Affichage des commentaires

// Initial state
const initialState = {
  currentQuestion: 0,
  score: 0,
  showScore: false,
  selectedOption: null,
  showFeedback: false, // New state for feedback
};
Copier après la connexion

Ceci affiche les commentaires après la sélection d'une réponse :

*Affiche si la réponse était correcte ou incorrecte
*Affiche la bonne réponse si elle est fausse
*Comprend une explication

Lien hébergé de l'application quiz

quiztechnicalwriting.vercel.app

Comparaison entre useState et useReducer

Feature useState useReducer
Best for Simple state Complex state logic
State Management Direct, using setState Managed through a reducer function
Boilerplate Code Minimal Requires more setup
State Update Inline with setState Managed by dispatch and reducer

Conclusion

useState et useReducer sont tous deux de puissants hooks pour gérer l'état des composants fonctionnels. useState est mieux adapté aux états simples, tandis que useReducer brille lors de la gestion de scénarios plus complexes où les mises à jour d'état sont étroitement liées. Le choix du bon dépend de la complexité de l'état que vous devez gérer.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal