> 웹 프론트엔드 > JS 튜토리얼 > useReducer 및 useState와 다른 점

useReducer 및 useState와 다른 점

Susan Sarandon
풀어 주다: 2024-10-30 20:04:30
원래의
711명이 탐색했습니다.

useReducer and how it is different from useState

목차

  1. 소개
  2. useState를 사용하는 경우
  3. useReducer를 사용해야 하는 경우
  4. 예 1: useState를 사용한 카운터 앱
  5. 예 2: useReducer를 사용한 카운터 앱
  6. 예 3: useReducer를 사용한 양식 입력 처리
  7. 예 4: useReducer를 사용하여 퀴즈 앱 구축
  8. useState와 useReducer 비교
  9. 결론

소개

React는 상태 관리를 위해 useState와 useReducer라는 두 가지 핵심 후크를 제공합니다. 둘 다 기능 구성 요소의 상태를 처리하도록 설계되었지만 서로 다른 시나리오에서 사용됩니다. 이 기사에서는 두 가지의 차이점을 살펴보고 각각을 사용해야 하는 경우를 강조하며 더 나은 이해를 위한 예시를 제공합니다

useState를 사용하는 경우

useState는 다음과 같은 경우 로컬 상태를 처리하기 위한 간단하고 효과적인 후크입니다.

  • 관리하기 쉬운 상태(부울, 숫자, 문자열 등)가 있습니다.
  • 최소한의 설정으로 상태를 직접 업데이트하고 싶습니다.
  • 상태에는 복잡한 전환이나 여러 변수에 대한 종속성이 없습니다.

기본 구문

const [state, setState] = useState(initialState);
로그인 후 복사
로그인 후 복사
  • 상태: 현재 상태
  • setState: 상태를 업데이트하는 함수
  • initialState:초기 상태

useReducer를 사용하는 경우

useReducer는 다음과 같은 경우에 유용합니다.

  • 상태 논리가 복잡합니다.
  • 여러 상태 업데이트는 서로 종속됩니다.

기본 구문

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

로그인 후 복사
로그인 후 복사
  • 상태: 현재 상태
  • 디스패치: 상태 업데이트를 트리거하기 위해 리듀서에 작업을 보내는 함수입니다.
  • 리듀서: 리듀서는 현재 상태와 액션이라는 두 가지 인수를 취하는 순수 함수입니다. 액션에 따라 새로운 상태를 반환합니다.

기본 구문

const reducer = (state, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { count: state.count + 1 };
        case 'DECREMENT':
            return { count: state.count - 1 };
        default:
            return state;
    }
}
로그인 후 복사
로그인 후 복사
  • 액션: 액션은 어떤 변화가 일어나야 하는지 설명하는 객체입니다
    일반적으로 type 속성이 있고 선택적으로 페이로드가 있습니다.
    type은 리듀서에게 어떤 종류의 상태 변경이 필요한지 알려줍니다.
    페이로드는 변경에 필요한 추가 데이터를 전달합니다.

  • InitialState: 초기 상태는 useState의 초기 상태와 같습니다.

예시 1 useState를 사용한 카운터 앱

const [state, setState] = useState(initialState);
로그인 후 복사
로그인 후 복사

설명

  • useState를 사용하여 카운트 값을 추적합니다.
  • 두 개의 버튼이 있습니다. 하나는 카운트 상태를 증가시키고 다른 하나는 감소시키는 것입니다.
  • 상태는 setCount 함수를 사용하여 직접 업데이트됩니다.

예 2: useReducer를 사용한 카운터 앱

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

로그인 후 복사
로그인 후 복사

설명

  • 리듀서 함수는 전달된 작업에 따라 상태가 어떻게 변경되어야 하는지 제어합니다.
  • 상태를 직접 설정하는 대신 변경 사항을 트리거하는 작업(증가, 감소)을 전달합니다.

예제 3: useReducer를 사용한 양식 입력 처리

여러 입력 필드가 있는 양식을 처리하는 개념으로 확장해 보겠습니다. 이 시나리오는 작업을 기반으로 여러 상태 속성을 업데이트하므로 useReducer에 이상적입니다.

const reducer = (state, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { count: state.count + 1 };
        case 'DECREMENT':
            return { count: state.count - 1 };
        default:
            return state;
    }
}
로그인 후 복사
로그인 후 복사

설명

  • 리듀서는 작업 유형에 따라 다양한 속성(이름, 이메일)을 업데이트하여 양식 상태를 관리합니다.
  • Dispatch는 상태를 업데이트하기 위해 리듀서에 작업을 보냅니다. 페이로드는 데이터(예: 입력 값)를 전달합니다.

예시 4: useReducer를 사용하여 퀴즈 앱 구축

참고: 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>
  );
}


로그인 후 복사

설명

*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>
  );
}

로그인 후 복사
  • 리듀서 기능
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>
  );
}




로그인 후 복사

감속기는 세 가지 작업을 처리합니다.

  • SELECT_OPTION: 사용자가 답변을 선택할 때
  • NEXT_QUESTION: 다음 질문으로 이동할 때
  • RESTART : 퀴즈를 다시 시작할 때

스타일링 로직

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;


로그인 후 복사

이 코드는 버튼 스타일을 결정합니다.

  • 기본값: 회색 배경
  • 정답: 녹색 배경에 녹색 테두리
  • 오답: 빨간색 배경에 빨간색 테두리

피드백 디스플레이

// Initial state
const initialState = {
  currentQuestion: 0,
  score: 0,
  showScore: false,
  selectedOption: null,
  showFeedback: false, // New state for feedback
};
로그인 후 복사

답변을 선택한 후 피드백이 표시됩니다.

*답변의 정답인지 오답인지 표시
*틀리면 정답을 보여줍니다
*설명이 포함되어 있습니다

퀴즈 앱의 호스팅 링크

퀴즈technicalwriting.vercel.app

useState와 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

결론

useState와 useReducer는 모두 기능적 구성 요소의 상태를 관리하기 위한 강력한 후크입니다. useState는 단순한 상태에 가장 적합하고, useReducer는 상태 업데이트가 밀접하게 관련된 더 복잡한 시나리오를 처리할 때 빛을 발합니다. 올바른 것을 선택하는 것은 관리해야 하는 상태의 복잡성에 따라 다릅니다.

위 내용은 useReducer 및 useState와 다른 점의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿