欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React?的?useReducer?和?Redux?的區(qū)別及什么情況下應(yīng)該使用?useReducer

 更新時(shí)間:2025年06月12日 09:15:14   作者:前端布洛芬  
這篇文章主要介紹了React的useReducer和Redux的區(qū)別及什么情況下應(yīng)該使用useReducer,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

大白話 JavaScript中事件委托中動(dòng)態(tài)節(jié)點(diǎn)的事件失效解決方案?

前端打工人的深夜加班,除了咖啡和布洛芬,最怕遇到什么?
是組件間傳值層層嵌套像"俄羅斯套娃",是復(fù)雜狀態(tài)管理邏輯寫得頭暈?zāi)X脹,是Redux樣板代碼多到懷疑人生……今天咱們就聊聊React狀態(tài)管理的兩大"神器"——useReducer和Redux,用最接地氣的話講清它們的區(qū)別和適用場(chǎng)景,看完這篇,你不僅能選對(duì)工具,還能和面試官嘮明白背后的邏輯~

一、狀態(tài)管理的"三大撓頭時(shí)刻"

先講個(gè)我上周改需求的真實(shí)經(jīng)歷:給電商項(xiàng)目的購(gòu)物車功能加"批量操作"。原本用useState管理狀態(tài),結(jié)果:

  • 狀態(tài)更新邏輯復(fù)雜:修改一個(gè)商品的選中狀態(tài),要同時(shí)計(jì)算總價(jià)、已選數(shù)量、更新商品列表,代碼寫了幾十行;
  • 組件間傳值混亂:從商品列表到購(gòu)物車組件,再到結(jié)算組件,一個(gè)狀態(tài)要經(jīng)過(guò)3層props傳遞,改個(gè)bug得在3個(gè)文件間來(lái)回切換;
  • 調(diào)試?yán)щy:狀態(tài)變化不透明,不知道哪個(gè)操作觸發(fā)了狀態(tài)更新,斷點(diǎn)都不知道打在哪。

這些問(wèn)題的根源,是簡(jiǎn)單的useState無(wú)法滿足復(fù)雜狀態(tài)管理的需求。而useReducer和Redux的出現(xiàn),就是來(lái)解決這些"狀態(tài)亂、傳值難、調(diào)試煩"的痛點(diǎn)的~

二、從"狀態(tài)機(jī)"到"數(shù)據(jù)流"的進(jìn)化

要搞懂useReducer和Redux的區(qū)別,得先明白它們的底層設(shè)計(jì)差異。簡(jiǎn)單說(shuō):

  • useReducer是"輕量級(jí)狀態(tài)機(jī)":通過(guò)一個(gè)純函數(shù)(reducer)處理狀態(tài)更新,把狀態(tài)和更新邏輯集中管理;
  • Redux是"單向數(shù)據(jù)流":通過(guò)store統(tǒng)一管理全局狀態(tài),action描述變化,reducer處理變化,middleware處理異步,形成單向數(shù)據(jù)流。

核心區(qū)別1:作用域不同

  • useReducer:組件級(jí)狀態(tài)管理,只在當(dāng)前組件及其子組件中有效;
  • Redux:全局狀態(tài)管理,所有組件都能訪問(wèn)和修改同一狀態(tài)。

核心區(qū)別2:復(fù)雜度不同

  • useReducer:輕量級(jí),只需定義reducer函數(shù)和action類型,適合中小規(guī)模狀態(tài)管理;
  • Redux:重量級(jí),需要store、reducer、action creator、middleware等,適合大型應(yīng)用和復(fù)雜狀態(tài)管理。

核心區(qū)別3:調(diào)試方式不同

  • useReducer:調(diào)試?yán)щy,狀態(tài)變化不透明,只能通過(guò)console.log或React DevTools查看;
  • Redux:調(diào)試簡(jiǎn)單,支持時(shí)間旅行調(diào)試(time-travel debugging),可記錄所有狀態(tài)變化。

核心區(qū)別4:異步處理不同

  • useReducer:不直接支持異步,需配合useEffect手動(dòng)處理;
  • Redux:通過(guò)middleware(如redux-thunk、redux-saga)支持復(fù)雜異步操作。

三、代碼示例:從"狀態(tài)混亂"到"井然有序"

示例1:簡(jiǎn)單計(jì)數(shù)器(useReducer vs useState)

用useReducer和useState實(shí)現(xiàn)一個(gè)簡(jiǎn)單的計(jì)數(shù)器,對(duì)比代碼復(fù)雜度。

useState實(shí)現(xiàn)

import React, { useState } from 'react';
function Counter() {
  // 定義狀態(tài)和更新函數(shù)
  const [count, setCount] = useState(0);
  // 增加計(jì)數(shù)的函數(shù)
  const increment = () => {
    setCount(count + 1);
  };
  // 減少計(jì)數(shù)的函數(shù)
  const decrement = () => {
    setCount(count - 1);
  };
  // 重置計(jì)數(shù)的函數(shù)
  const reset = () => {
    setCount(0);
  };
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

useReducer實(shí)現(xiàn)

import React, { useReducer } from 'react';
// 定義action類型
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const RESET = 'RESET';
// 定義reducer函數(shù)
const counterReducer = (state, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    case DECREMENT:
      return state - 1;
    case RESET:
      return 0;
    default:
      return state;
  }
};
function Counter() {
  // 使用useReducer初始化狀態(tài)和dispatch函數(shù)
  const [count, dispatch] = useReducer(counterReducer, 0);
  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch({ type: INCREMENT })}>+</button>
      <button onClick={() => dispatch({ type: DECREMENT })}>-</button>
      <button onClick={() => dispatch({ type: RESET })}>Reset</button>
    </div>
  );
}

對(duì)比

  • useState:代碼簡(jiǎn)單,但狀態(tài)更新邏輯分散在各個(gè)函數(shù)中;
  • useReducer:代碼稍復(fù)雜,但狀態(tài)更新邏輯集中在reducer中,便于維護(hù)和測(cè)試。

示例2:購(gòu)物車(useReducer vs Redux)

用useReducer和Redux實(shí)現(xiàn)一個(gè)簡(jiǎn)單的購(gòu)物車,對(duì)比代碼復(fù)雜度和狀態(tài)管理方式。

useReducer實(shí)現(xiàn)

import React, { useReducer } from 'react';
// 定義action類型
const ADD_TO_CART = 'ADD_TO_CART';
const REMOVE_FROM_CART = 'REMOVE_FROM_CART';
const UPDATE_QUANTITY = 'UPDATE_QUANTITY';
const CLEAR_CART = 'CLEAR_CART';
// 定義reducer函數(shù)
const cartReducer = (state, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      // 檢查商品是否已在購(gòu)物車中
      const existingItem = state.find(item => item.id === action.payload.id);
      if (existingItem) {
        // 如果已存在,增加數(shù)量
        return state.map(item => 
          item.id === action.payload.id 
            ? { ...item, quantity: item.quantity + 1 } 
            : item
        );
      } else {
        // 如果不存在,添加新商品
        return [...state, { ...action.payload, quantity: 1 }];
      }
    case REMOVE_FROM_CART:
      // 移除商品
      return state.filter(item => item.id !== action.payload);
    case UPDATE_QUANTITY:
      // 更新商品數(shù)量
      return state.map(item => 
        item.id === action.payload.id 
          ? { ...item, quantity: action.payload.quantity } 
          : item
      );
    case CLEAR_CART:
      // 清空購(gòu)物車
      return [];
    default:
      return state;
  }
};
function ShoppingCart() {
  // 使用useReducer初始化購(gòu)物車狀態(tài)
  const [cart, dispatch] = useReducer(cartReducer, []);
  // 計(jì)算購(gòu)物車總價(jià)
  const totalPrice = cart.reduce((total, item) => 
    total + item.price * item.quantity, 0);
  return (
    <div>
      <h1>Shopping Cart</h1>
      <ul>
        {cart.map(item => (
          <li key={item.id}>
            {item.name} x {item.quantity} = ${item.price * item.quantity}
            <button onClick={() => dispatch({ 
              type: UPDATE_QUANTITY, 
              payload: { id: item.id, quantity: item.quantity + 1 } 
            })}>+</button>
            <button onClick={() => dispatch({ 
              type: UPDATE_QUANTITY, 
              payload: { id: item.id, quantity: Math.max(1, item.quantity - 1) } 
            })}>-</button>
            <button onClick={() => dispatch({ 
              type: REMOVE_FROM_CART, 
              payload: item.id 
            })}>Remove</button>
          </li>
        ))}
      </ul>
      <p>Total: ${totalPrice}</p>
      <button onClick={() => dispatch({ type: CLEAR_CART })}>Clear Cart</button>
    </div>
  );
}

Redux實(shí)現(xiàn)

// actions.js
// 定義action類型常量
export const ADD_TO_CART = 'ADD_TO_CART';
export const REMOVE_FROM_CART = 'REMOVE_FROM_CART';
export const UPDATE_QUANTITY = 'UPDATE_QUANTITY';
export const CLEAR_CART = 'CLEAR_CART';
// 定義action creator函數(shù)
export const addToCart = (product) => ({
  type: ADD_TO_CART,
  payload: product
});
export const removeFromCart = (productId) => ({
  type: REMOVE_FROM_CART,
  payload: productId
});
export const updateQuantity = (productId, quantity) => ({
  type: UPDATE_QUANTITY,
  payload: { productId, quantity }
});
export const clearCart = () => ({
  type: CLEAR_CART
});
// reducers.js
import { ADD_TO_CART, REMOVE_FROM_CART, UPDATE_QUANTITY, CLEAR_CART } from './actions';
// 定義初始狀態(tài)
const initialState = [];
// 定義reducer函數(shù)
const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      const existingItem = state.find(item => item.id === action.payload.id);
      if (existingItem) {
        return state.map(item => 
          item.id === action.payload.id 
            ? { ...item, quantity: item.quantity + 1 } 
            : item
        );
      } else {
        return [...state, { ...action.payload, quantity: 1 }];
      }
    case REMOVE_FROM_CART:
      return state.filter(item => item.id !== action.payload);
    case UPDATE_QUANTITY:
      return state.map(item => 
        item.id === action.payload.productId 
          ? { ...item, quantity: action.payload.quantity } 
          : item
      );
    case CLEAR_CART:
      return [];
    default:
      return state;
  }
};
export default cartReducer;
// store.js
import { createStore } from 'redux';
import cartReducer from './reducers';
// 創(chuàng)建store
const store = createStore(cartReducer);
export default store;
// CartComponent.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addToCart, removeFromCart, updateQuantity, clearCart } from './actions';
function ShoppingCart() {
  // 獲取store中的狀態(tài)
  const cart = useSelector(state => state);
  const dispatch = useDispatch();
  // 計(jì)算購(gòu)物車總價(jià)
  const totalPrice = cart.reduce((total, item) => 
    total + item.price * item.quantity, 0);
  return (
    <div>
      <h1>Shopping Cart</h1>
      <ul>
        {cart.map(item => (
          <li key={item.id}>
            {item.name} x {item.quantity} = ${item.price * item.quantity}
            <button onClick={() => dispatch(updateQuantity(item.id, item.quantity + 1))}>+</button>
            <button onClick={() => dispatch(updateQuantity(item.id, Math.max(1, item.quantity - 1)))}>-</button>
            <button onClick={() => dispatch(removeFromCart(item.id))}>Remove</button>
          </li>
        ))}
      </ul>
      <p>Total: ${totalPrice}</p>
      <button onClick={() => dispatch(clearCart())}>Clear Cart</button>
    </div>
  );
}

對(duì)比

  • useReducer:代碼集中在一個(gè)組件中,適合局部狀態(tài)管理;
  • Redux:代碼分散在多個(gè)文件中,適合全局狀態(tài)管理,但需要更多樣板代碼。

四 、一張表看核心差異

對(duì)比項(xiàng)useReducerRedux
作用域組件級(jí)全局
復(fù)雜度輕量級(jí),簡(jiǎn)單邏輯重量級(jí),復(fù)雜邏輯
樣板代碼多(action、reducer、store)
調(diào)試難度較難容易(時(shí)間旅行調(diào)試)
異步處理需手動(dòng)處理有專門的middleware處理
學(xué)習(xí)成本
適用場(chǎng)景局部復(fù)雜狀態(tài)、表單處理全局狀態(tài)、跨組件通信、時(shí)間旅行調(diào)試

五、面試題回答方法 正常回答(結(jié)構(gòu)化):

“React的useReducer和Redux的主要區(qū)別在于:

  • 作用域不同:useReducer是組件級(jí)的狀態(tài)管理,Redux是全局狀態(tài)管理;
  • 復(fù)雜度不同:useReducer輕量級(jí),適合簡(jiǎn)單到中等復(fù)雜度的狀態(tài)管理;Redux重量級(jí),適合大型應(yīng)用和復(fù)雜狀態(tài)管理;
  • 調(diào)試方式不同:useReducer調(diào)試?yán)щy,Redux支持時(shí)間旅行調(diào)試;
  • 異步處理不同:useReducer需手動(dòng)處理異步,Redux有專門的middleware處理異步。

當(dāng)遇到以下情況時(shí),應(yīng)該使用useReducer:

  • 狀態(tài)更新邏輯復(fù)雜,包含多個(gè)子值或下一個(gè)狀態(tài)依賴于之前的狀態(tài);
  • 組件需要處理復(fù)雜的表單狀態(tài);
  • 狀態(tài)邏輯需要被測(cè)試,且不需要全局共享;
  • 需要局部狀態(tài)管理,而不需要引入Redux的復(fù)雜性。”

大白話回答(接地氣):

“useReducer就像你家里的小賬本,只記錄你自己的收支情況,簡(jiǎn)單直接,不需要讓別人知道。
Redux就像公司的財(cái)務(wù)系統(tǒng),所有人的收支都記錄在里面,雖然復(fù)雜但透明,而且大家都能看到和修改。

當(dāng)你需要:

  • 自己處理復(fù)雜的收支計(jì)算(復(fù)雜狀態(tài)邏輯);
  • 管理自己的私房錢(局部狀態(tài));
  • 不想讓別人知道你的財(cái)務(wù)狀況(不需要全局共享);
  • 不想學(xué)習(xí)復(fù)雜的財(cái)務(wù)系統(tǒng)(降低學(xué)習(xí)成本);
  • 這時(shí)候就用useReducer。”

六、總結(jié):4個(gè)使用原則+2個(gè)避坑指南

4個(gè)使用原則:

  • 局部狀態(tài)用useReducer:組件內(nèi)部的復(fù)雜狀態(tài)管理,無(wú)需跨組件共享;
  • 全局狀態(tài)用Redux:多個(gè)組件需要共享狀態(tài),或需要時(shí)間旅行調(diào)試;
  • 簡(jiǎn)單狀態(tài)用useState:狀態(tài)更新邏輯簡(jiǎn)單,不需要復(fù)雜的reducer;
  • 復(fù)雜異步用Redux:涉及復(fù)雜異步操作(如API調(diào)用、事務(wù)處理),使用Redux middleware。

2個(gè)避坑指南:

  • 別過(guò)度使用useReducer:如果狀態(tài)更新邏輯簡(jiǎn)單,直接用useState更清晰;
  • 別盲目使用Redux:小型項(xiàng)目或不需要全局狀態(tài)的項(xiàng)目,引入Redux會(huì)增加不必要的復(fù)雜度。

七、擴(kuò)展思考:4個(gè)高頻問(wèn)題解答

問(wèn)題1:useReducer和useState有什么關(guān)系?

解答:useReducer是useState的替代方案,當(dāng)狀態(tài)更新邏輯復(fù)雜時(shí),useReducer更具優(yōu)勢(shì)。實(shí)際上,useState內(nèi)部就是基于useReducer實(shí)現(xiàn)的。當(dāng)你需要:

  • 下一個(gè)狀態(tài)依賴于之前的狀態(tài);
  • 狀態(tài)包含多個(gè)子值;
  • 狀態(tài)更新邏輯復(fù)雜;
    這時(shí)候useReducer比useState更合適。

問(wèn)題2:Redux和Context API有什么區(qū)別?

解答:Redux和Context API都可以實(shí)現(xiàn)全局狀態(tài)管理,但有以下區(qū)別:

  • Redux:?jiǎn)蜗驍?shù)據(jù)流,狀態(tài)更新可預(yù)測(cè),支持時(shí)間旅行調(diào)試,適合大型應(yīng)用;
  • Context API:簡(jiǎn)單的狀態(tài)共享,不強(qiáng)制單向數(shù)據(jù)流,調(diào)試?yán)щy,適合簡(jiǎn)單的狀態(tài)共享。

簡(jiǎn)單說(shuō),Redux是"重型武器",Context API是"輕武器"。

問(wèn)題3:useReducer可以替代Redux嗎?

解答:在某些場(chǎng)景下可以,但不是全部。useReducer適合局部狀態(tài)管理,而Redux適合全局狀態(tài)管理。當(dāng)你需要:

  • 全局狀態(tài)共享;
  • 時(shí)間旅行調(diào)試;
  • 復(fù)雜異步處理;
  • 狀態(tài)變更歷史記錄;
    Redux仍然是更好的選擇。

問(wèn)題4:如何在項(xiàng)目中選擇合適的狀態(tài)管理方案?

解答:可以按照以下流程選擇:

  • 狀態(tài)是否需要跨組件共享?
    • 否 → 使用useState或useReducer;
    • 是 → 繼續(xù)下一步。
  • 狀態(tài)管理邏輯是否復(fù)雜?
    • 否 → 使用Context API;
    • 是 → 繼續(xù)下一步。
  • 是否需要時(shí)間旅行調(diào)試或復(fù)雜異步處理?
    • 否 → 使用useContext + useReducer;
    • 是 → 使用Redux或MobX。

結(jié)尾:用對(duì)工具,狀態(tài)管理不"鬧心"

useReducer和Redux不是非此即彼的選擇,而是互補(bǔ)的工具。掌握它們的核心區(qū)別和適用場(chǎng)景,能讓你在前端路上走得更穩(wěn)、更順~

下次寫組件時(shí),不妨先問(wèn)問(wèn)自己:這個(gè)狀態(tài)是局部的還是全局的?更新邏輯復(fù)雜嗎?需要時(shí)間旅行調(diào)試嗎?然后再選擇合適的工具,你會(huì)發(fā)現(xiàn)狀態(tài)管理從"鬧心"變"順心"~如果這篇文章幫你理清了思路,記得點(diǎn)個(gè)收藏,咱們下期,不見不散!

到此這篇關(guān)于React 的 useReducer 和 Redux 的區(qū)別?什么情況下應(yīng)該使用 useReducer?的文章就介紹到這了,更多相關(guān)React useReducer 和 Redux區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React 18版本配置rem 和 vw的詳細(xì)步驟

    React 18版本配置rem 和 vw的詳細(xì)步驟

    這篇文章主要介紹了React 18版本配置rem 和 vw的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • 使用React組件編寫溫度顯示器

    使用React組件編寫溫度顯示器

    這篇文章主要為大家詳細(xì)介紹了使用React組件編寫溫度顯示器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • react調(diào)試和測(cè)試代碼的小技巧

    react調(diào)試和測(cè)試代碼的小技巧

    在開發(fā)React應(yīng)用時(shí),嚴(yán)格模式StrictMode可以幫助開發(fā)者捕捉到組件中的錯(cuò)誤和潛在問(wèn)題,安裝React Developer Tools瀏覽器擴(kuò)展檢查組件的props和狀態(tài),直接修改以及分析性能,@testing-library/react和Cypress或Playwright等工具可以有效地測(cè)試React組件和執(zhí)行端到端測(cè)試
    2024-10-10
  • react電商商品列表的實(shí)現(xiàn)流程詳解

    react電商商品列表的實(shí)現(xiàn)流程詳解

    這篇文章主要介紹了react實(shí)現(xiàn)電商商品列表的流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • mobx在react hooks中的應(yīng)用方式

    mobx在react hooks中的應(yīng)用方式

    這篇文章主要介紹了mobx在react hooks中的應(yīng)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • React反向代理與CSS模塊化的使用案例

    React反向代理與CSS模塊化的使用案例

    這篇文章主要介紹了React反向代理與CSS模塊化的使用案例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02
  • 在react-router4中進(jìn)行代碼拆分的方法(基于webpack)

    在react-router4中進(jìn)行代碼拆分的方法(基于webpack)

    這篇文章主要介紹了在react-router4中進(jìn)行代碼拆分的方法(基于webpack),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • React高級(jí)指引之Refs and the DOM使用時(shí)機(jī)詳解

    React高級(jí)指引之Refs and the DOM使用時(shí)機(jī)詳解

    在典型的React數(shù)據(jù)流中,props是父組件與子組件交互的唯一方式。要修改一個(gè)子組件,你需要使用新的props來(lái)重新渲染它。但是,在某些情況下,你需要在典型數(shù)據(jù)流之外強(qiáng)制修改子組件
    2023-02-02
  • 詳解React的組件通訊

    詳解React的組件通訊

    這篇文章主要介紹了詳解react組件通訊方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • react實(shí)現(xiàn)拖拽模態(tài)框

    react實(shí)現(xiàn)拖拽模態(tài)框

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)拖拽模態(tài)框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評(píng)論