亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

示例1:簡單計數(shù)器(useReducer vs useState)

用useReducer和useState實現(xiàn)一個簡單的計數(shù)器,對比代碼復雜度。

useState實現(xiàn)

import React, { useState } from 'react';
function Counter() {
  // 定義狀態(tài)和更新函數(shù)
  const [count, setCount] = useState(0);
  // 增加計數(shù)的函數(shù)
  const increment = () => {
    setCount(count + 1);
  };
  // 減少計數(shù)的函數(shù)
  const decrement = () => {
    setCount(count - 1);
  };
  // 重置計數(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實現(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>
  );
}

對比

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

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

用useReducer和Redux實現(xiàn)一個簡單的購物車,對比代碼復雜度和狀態(tài)管理方式。

useReducer實現(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:
      // 檢查商品是否已在購物車中
      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:
      // 清空購物車
      return [];
    default:
      return state;
  }
};
function ShoppingCart() {
  // 使用useReducer初始化購物車狀態(tài)
  const [cart, dispatch] = useReducer(cartReducer, []);
  // 計算購物車總價
  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實現(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();
  // 計算購物車總價
  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>
  );
}

對比

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

四 、一張表看核心差異

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

五、面試題回答方法 正?;卮穑ńY(jié)構(gòu)化):

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

  • 作用域不同:useReducer是組件級的狀態(tài)管理,Redux是全局狀態(tài)管理;
  • 復雜度不同:useReducer輕量級,適合簡單到中等復雜度的狀態(tài)管理;Redux重量級,適合大型應用和復雜狀態(tài)管理;
  • 調(diào)試方式不同:useReducer調(diào)試困難,Redux支持時間旅行調(diào)試;
  • 異步處理不同:useReducer需手動處理異步,Redux有專門的middleware處理異步。

當遇到以下情況時,應該使用useReducer:

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

大白話回答(接地氣):

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

當你需要:

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

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

4個使用原則:

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

2個避坑指南:

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

七、擴展思考:4個高頻問題解答

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

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

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

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

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

  • Redux:單向數(shù)據(jù)流,狀態(tài)更新可預測,支持時間旅行調(diào)試,適合大型應用;
  • Context API:簡單的狀態(tài)共享,不強制單向數(shù)據(jù)流,調(diào)試困難,適合簡單的狀態(tài)共享。

簡單說,Redux是"重型武器",Context API是"輕武器"。

問題3:useReducer可以替代Redux嗎?

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

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

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

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

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

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

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

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

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

相關(guān)文章

  • React 18版本配置rem 和 vw的詳細步驟

    React 18版本配置rem 和 vw的詳細步驟

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

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

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

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

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

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

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

    mobx在react hooks中的應用方式

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

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

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

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

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

    React高級指引之Refs and the DOM使用時機詳解

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

    詳解React的組件通訊

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

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

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

最新評論