最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)目的購物車功能加"批量操作"。原本用useState管理狀態(tài),結(jié)果:

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

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

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

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

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

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

  • useReducer:組件級(jí)狀態(tài)管理,只在當(dāng)前組件及其子組件中有效;
  • Redux:全局狀態(tài)管理,所有組件都能訪問和修改同一狀態(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)變化不透明,只能通過console.log或React DevTools查看;
  • Redux:調(diào)試簡單,支持時(shí)間旅行調(diào)試(time-travel debugging),可記錄所有狀態(tài)變化。

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

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

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

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

用useReducer和useState實(shí)現(xiàn)一個(gè)簡單的計(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:代碼簡單,但狀態(tài)更新邏輯分散在各個(gè)函數(shù)中;
  • useReducer:代碼稍復(fù)雜,但狀態(tài)更新邏輯集中在reducer中,便于維護(hù)和測(cè)試。

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

用useReducer和Redux實(shí)現(xiàn)一個(gè)簡單的購物車,對(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:
      // 檢查商品是否已在購物車中
      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, []);
  // 計(jì)算購物車總價(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ì)算購物車總價(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í),簡單邏輯重量級(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í),適合簡單到中等復(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就像你家里的小賬本,只記錄你自己的收支情況,簡單直接,不需要讓別人知道。
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)管理,無需跨組件共享;
  • 全局狀態(tài)用Redux:多個(gè)組件需要共享狀態(tài),或需要時(shí)間旅行調(diào)試;
  • 簡單狀態(tài)用useState:狀態(tài)更新邏輯簡單,不需要復(fù)雜的reducer;
  • 復(fù)雜異步用Redux:涉及復(fù)雜異步操作(如API調(diào)用、事務(wù)處理),使用Redux middleware。

2個(gè)避坑指南:

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

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

問題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更合適。

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

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

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

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

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

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

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

問題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í),不妨先問問自己:這個(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)文章

  • webpack4 + react 搭建多頁面應(yīng)用示例

    webpack4 + react 搭建多頁面應(yīng)用示例

    這篇文章主要介紹了webpack4 + react 搭建多頁面應(yīng)用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • React RenderProps模式運(yùn)用過程淺析

    React RenderProps模式運(yùn)用過程淺析

    render props是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的技術(shù)。簡單來說,給一個(gè)組件傳入一個(gè)prop,這個(gè)props是一個(gè)函數(shù),函數(shù)的作用是用來告訴這個(gè)組件需要渲染什么內(nèi)容,那么這個(gè)prop就成為render prop
    2023-03-03
  • create-react-app如何降低react的版本

    create-react-app如何降低react的版本

    這篇文章主要介紹了create-react-app降低react的版本方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 解決React報(bào)錯(cuò)Expected an assignment or function call and instead saw an expression

    解決React報(bào)錯(cuò)Expected an assignment or funct

    這篇文章主要為大家介紹了React報(bào)錯(cuò)Expected an assignment or function call and instead saw an expression解決方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 一文詳解React中如何實(shí)現(xiàn)組件懶加載

    一文詳解React中如何實(shí)現(xiàn)組件懶加載

    懶加載是一種優(yōu)化技術(shù),旨在延遲加載不必要的資源,直到它們真正需要時(shí)再進(jìn)行加載,那么React的懶加載是如何實(shí)現(xiàn)的呢,下面小編就來和大家詳細(xì)講講吧
    2025-03-03
  • React樣式?jīng)_突解決問題的方法

    React樣式?jīng)_突解決問題的方法

    本文主要介紹了React樣式?jīng)_突解決問題的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • react-router實(shí)現(xiàn)按需加載

    react-router實(shí)現(xiàn)按需加載

    本篇文章主要介紹了react-router實(shí)現(xiàn)按需加載,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • React組件間傳值及跨組件通信詳解

    React組件間傳值及跨組件通信詳解

    這篇文章主要介紹了React組件間傳值及跨組件通信的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • 初識(shí)React及React開發(fā)依賴詳解

    初識(shí)React及React開發(fā)依賴詳解

    React由Facebook來更新和維護(hù),它是大量優(yōu)秀程序員的思想結(jié)晶,React的流行不僅僅局限于普通開發(fā)工程師對(duì)它的認(rèn)可,大量流行的其他框架借鑒React的思想,接下來通過本文介紹React基礎(chǔ)及React開發(fā)依賴介紹,需要的朋友可以參考下
    2022-10-10
  • 解決React在安裝antd之后出現(xiàn)的Can''t resolve ''./locale''問題(推薦)

    解決React在安裝antd之后出現(xiàn)的Can''t resolve ''./locale''問題(推薦)

    這篇文章主要介紹了解決React在安裝antd之后出現(xiàn)的Can't resolve './locale'問題,本文給大家分享解決方案,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05

最新評(píng)論

上杭县| 龙州县| 伊宁县| 永川市| 昭平县| 乌鲁木齐市| 黎川县| 绥宁县| 咸宁市| 和田市| 久治县| 浪卡子县| 井陉县| 互助| 天峻县| 北川| 安岳县| 甘洛县| 曲阜市| 思南县| 樟树市| 建德市| 双柏县| 内黄县| 中宁县| 台山市| 房山区| 昭觉县| 翁牛特旗| 佛坪县| 海伦市| 西乡县| 平度市| 二连浩特市| 全南县| 昌平区| 怀远县| 资源县| 富平县| 湖北省| 错那县|