首頁 > web前端 > 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);

登入後複製
登入後複製
  • 狀態:目前狀態。
  • dispatch:向reducer發送動作以觸發狀態更新的函數。
  • reducer:reducer 是一個純函數,它接受兩個參數:目前狀態和運算。 它根據操作返回新狀態。

基本文法

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 屬性和可選的 payload.
    類型告訴reducer要進行什麼樣的狀態改變。
    有效負載攜帶更改所需的任何附加資料。

  • InitialState:初始狀態,就像useState中的initialstate一樣。

範例 1 帶有 useState 的計數器應用程式

const [state, setState] = useState(initialState);
登入後複製
登入後複製

解釋

  • 我們使用 useState 來追蹤計數值。
  • 我們有兩個按鈕:一個用來增加計數狀態,一個用來減少計數狀態。
  • 直接使用setCount函數更新狀態。

範例 2:帶有 useReducer 的計數器應用程式

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

登入後複製
登入後複製

解釋

  • reducer 函數控制狀態應如何根據分派的操作進行變更。
  • 我們不直接設定狀態,而是調度操作(遞增、遞減)來觸發變更。

範例 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;
    }
}
登入後複製
登入後複製

解釋

  • reducer 透過根據操作的類型更新不同的屬性(姓名、電子郵件)來管理表單狀態。
  • Dispatch 將操作傳送到reducer 以更新狀態。有效負載攜帶資料(例如輸入值)。

範例 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
};
登入後複製

這顯示了選擇答案後的回饋:

*顯示答案是否正確
*如果錯誤則顯示正確答案
*包括解釋

測驗應用程式的託管鏈接

測驗技術寫作.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
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板