MST

星途 面试题库

面试题:React函数组件中复杂状态管理与useReducer的应用

假设你正在开发一个购物车功能,购物车中商品的数量、价格等状态需要进行复杂的计算和更新操作。请说明为什么在这种场景下使用useReducer比useState更合适,并给出具体的实现代码示例,包括reducer函数和初始状态的设置。
38.9万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

使用useReducer比useState更合适的原因

  1. 状态管理复杂性:当购物车商品数量、价格等状态涉及复杂计算和更新逻辑时,useReducer将所有更新逻辑集中在一个reducer函数中,相比useState分散的状态更新逻辑,更易于维护和理解。
  2. 可追溯性reducer函数接收前一个状态和一个动作对象,动作对象可以清晰描述状态变化的意图,方便追踪状态变化过程,而useState在复杂逻辑下状态变化较难追踪。
  3. 代码结构useReducer有助于将组件逻辑和状态更新逻辑分离,使组件代码结构更清晰,特别是在购物车这样状态变化复杂的场景。

实现代码示例

import React, { useReducer } from 'react';

// 定义初始状态
const initialState = {
  items: [],
  totalPrice: 0,
  totalQuantity: 0
};

// 定义reducer函数
const cartReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      const newItem = action.payload;
      const existingItemIndex = state.items.findIndex(item => item.id === newItem.id);
      let updatedItems;
      let updatedTotalQuantity;
      let updatedTotalPrice;
      if (existingItemIndex >= 0) {
        const existingItem = state.items[existingItemIndex];
        updatedItems = [...state.items];
        updatedItems[existingItemIndex] = {
          ...existingItem,
          quantity: existingItem.quantity + newItem.quantity
        };
        updatedTotalQuantity = state.totalQuantity + newItem.quantity;
        updatedTotalPrice = state.totalPrice + newItem.price * newItem.quantity;
      } else {
        updatedItems = [...state.items, {...newItem }];
        updatedTotalQuantity = state.totalQuantity + newItem.quantity;
        updatedTotalPrice = state.totalPrice + newItem.price * newItem.quantity;
      }
      return {
        items: updatedItems,
        totalPrice: updatedTotalPrice,
        totalQuantity: updatedTotalQuantity
      };
    case 'REMOVE_ITEM':
      const itemToRemove = action.payload;
      const itemIndex = state.items.findIndex(item => item.id === itemToRemove.id);
      const itemToDelete = state.items[itemIndex];
      let newTotalQuantity = state.totalQuantity - itemToDelete.quantity;
      let newTotalPrice = state.totalPrice - itemToDelete.price * itemToDelete.quantity;
      let newItems;
      if (itemToDelete.quantity > 1) {
        newItems = [...state.items];
        newItems[itemIndex] = {
          ...itemToDelete,
          quantity: itemToDelete.quantity - 1
        };
      } else {
        newItems = state.items.filter(item => item.id !== itemToRemove.id);
      }
      return {
        items: newItems,
        totalPrice: newTotalPrice,
        totalQuantity: newTotalQuantity
      };
    default:
      return state;
  }
};

const ShoppingCart = () => {
  const [cartState, dispatch] = useReducer(cartReducer, initialState);

  const addItemToCart = (item) => {
    dispatch({ type: 'ADD_ITEM', payload: item });
  };

  const removeItemFromCart = (item) => {
    dispatch({ type: 'REMOVE_ITEM', payload: item });
  };

  return (
    <div>
      <h1>Shopping Cart</h1>
      <ul>
        {cartState.items.map(item => (
          <li key={item.id}>
            {item.name} - Quantity: {item.quantity} - Price: {item.price * item.quantity}
            <button onClick={() => removeItemFromCart(item)}>Remove</button>
          </li>
        ))}
      </ul>
      <p>Total Quantity: {cartState.totalQuantity}</p>
      <p>Total Price: {cartState.totalPrice}</p>
      <button onClick={() => addItemToCart({ id: 1, name: 'Sample Product', quantity: 1, price: 10 })}>Add Item</button>
    </div>
  );
};

export default ShoppingCart;