React状态管理

发布于:2025-03-24 ⋅ 阅读:(29) ⋅ 点赞:(0)

状态管理

概念

状态管理是指如何高效地管理和共享组件中的状态。React 提供了 useStateuseReducer 来管理本地状态,而对于全局状态,可以使用 Context API 或第三方库(如 Redux)。

用法

  • 本地状态:使用 useState 或 useReducer
  • 全局状态:使用 Context API 或 Redux。

使用场景

  • 本地状态:组件内部的状态,如表单输入、按钮点击。
  • 全局状态:需要跨组件共享的状态,如用户登录信息、主题设置。
代码示例
// 1. 使用 Context API 管理全局状态
const ThemeContext = React.createContext('light');

function App() {
  const [theme, setTheme] = React.useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={theme}>
      <Toolbar toggleTheme={toggleTheme} />
    </ThemeContext.Provider>
  );
}

function Toolbar({ toggleTheme }) {
  return (
    <div>
      <ThemedButton toggleTheme={toggleTheme} />
    </div>
  );
}

function ThemedButton({ toggleTheme }) {
  const theme = React.useContext(ThemeContext);

  return (
    <button
      onClick={toggleTheme}
      style={{ background: theme === 'dark' ? '#333' : '#fff', color: theme === 'dark' ? '#fff' : '#333' }}
    >
      Toggle Theme
    </button>
  );
}

 

代码解析

  • ThemeContext.Provider:提供全局状态 theme
  • useContext:在子组件中获取 theme 状态。
  • toggleTheme:通过父组件传递回调函数来更新状态。

下面使用一个功能来说明状态管理的用法

实现功能

  1. 商品列表:显示用户可以购买的商品。
  2. 购物车:显示用户已添加的商品,并计算总价。
  3. 添加商品:用户点击商品时将其添加到购物车。
  4. 移除商品:用户可以点击按钮从购物车中移除商品。

代码实现

1. 创建 CartContext 管理全局状态
// src/contexts/CartContext.js
import React, { createContext, useReducer, useContext } from 'react';

// 创建 Context
const CartContext = createContext();

// 定义 initialState 初始状态
const initialState = {
  cartItems: [], // 购物车中的商品
};

// 定义 Reducer 函数,用于处理状态更新
function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD_ITEM':
      // 检查商品是否已经存在于购物车中
      const existingItem = state.cartItems.find(item => item.id === action.payload.id);
      if (existingItem) {
        // 如果存在,更新数量
        return {
          ...state,
          cartItems: state.cartItems.map(item =>
            item.id === action.payload.id ? { ...item, quantity: item.quantity + 1 } : item
          ),
        };
      } else {
        // 如果不存在,添加新商品
        return {
          ...state,
          cartItems: [...state.cartItems, { ...action.payload, quantity: 1 }],
        };
      }
    case 'REMOVE_ITEM':
      // 移除商品
      return {
        ...state,
        cartItems: state.cartItems.filter(item => item.id !== action.payload.id),
      };
    default:
      return state;
  }
}

// 创建 Provider 组件,用于包裹应用并提供全局状态
export function CartProvider({ children }) {
  const [state, dispatch] = useReducer(cartReducer, initialState); // 使用 useReducer 管理状态

  return (
    <CartContext.Provider value={{ state, dispatch }}>
      {
2. 创建商品列表组件
// src/components/ProductList.js
import React from 'react';
import { useCart } from '../contexts/CartContext'; // 引入 useCart Hook

const products = [
  { id: 1, name: '商品 1', price: 10 },
  { id: 2, name: '商品 2', price: 20 },
  { id: 3, name: '商品 3', price: 30 },
];

function ProductList() {
  const { dispatch } = useCart(); // 获取 dispatch 函数

  const handleAddToCart = product => {
    dispatch({ type: 'ADD_ITEM', payload: product }); // 触发 ADD_ITEM 动作
  };

  return (
    <div>
      <h2>商品列表</h2>
      <ul>
        {products.map(product => (
          <li key={product.id}>
            {product.name} - ¥{product.price}
            <button onClick={() => handleAddToCart(product)}>添加到购物车</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ProductList;
3. 创建购物车组件
// src/components/Cart.js
import React from 'react';
import { useCart } from '../contexts/CartContext'; // 引入 useCart Hook

function Cart() {
  const { state, dispatch } = useCart(); // 获取 state 和 dispatch

  const handleRemoveFromCart = item => {
    dispatch({ type: 'REMOVE_ITEM', payload: item }); // 触发 REMOVE_ITEM 动作
  };

  // 计算购物车总价
  const totalPrice = state.cartItems.reduce((total, item) => total + item.price * item.quantity, 0);

  return (
    <div>
      <h2>购物车</h2>
      {state.cartItems.length === 0 ? ( // 如果购物车为空,显示提示信息
        <p>购物车为空</p>
      ) : (
        <ul>
          {state.cartItems.map(item => (
            <li key={item.id}>
              {item.name} - ¥{item.price} x {item.quantity}
              <button onClick={() => handleRemoveFromCart(item)}>移除</button>
            </li>
          ))}
        </ul>
      )}
      <h3>总价: ¥{totalPrice}</h3>
    </div>
  );
}

export default Cart;
 4. 在主应用中使用 CartProvider 包裹组件
// src/App.js
import React from 'react';
import { CartProvider } from './contexts/CartContext'; // 引入 CartProvider
import ProductList from './components/ProductList'; // 引入商品列表组件
import Cart from './components/Cart'; // 引入购物车组件

function App() {
  return (
    <CartProvider> // 使用 CartProvider 包裹应用,提供全局状态
      <div>
        <h1>购物车应用</h1>
        <ProductList />
        <Cart />
      </div>
    </CartProvider>
  );
}

export default App;

 

代码解析

  1. CartContext

    • 使用 createContext 创建上下文。
    • 使用 useReducer 管理状态,定义 ADD_ITEM 和 REMOVE_ITEM 两种动作。
    • CartProvider 包裹整个应用,提供全局状态。
  2. ProductList

    • 显示商品列表,点击按钮将商品添加到购物车。
    • 使用 dispatch 触发 ADD_ITEM 动作。
  3. Cart

    • 显示购物车中的商品和总价。
    • 使用 dispatch 触发 REMOVE_ITEM 动作。
  4. App

    • 使用 CartProvider 包裹应用,使全局状态在 ProductList 和 Cart 之间共享。

运行效果

  • 用户可以从商品列表中添加商品到购物车。
  • 购物车会显示已添加的商品和总价。
  • 用户可以点击“移除”按钮从购物车中删除商品。

 

总结

通过这个例子,我们学习了如何使用 Context APIuseReducer 管理全局状态:

  • 状态管理:将购物车的状态和逻辑集中管理。
  • 组件复用:商品列表和购物车组件各自独立,但共享相同的状态。
  • 代码结构清晰:将上下文、组件和主应用分离,易于维护和扩展。

通过模块化的方式进行管理实现

实现思路

  1. state:单独定义全局状态。
  2. actions:定义操作状态的函数。
  3. reducer:处理状态更新逻辑。
  4. store:创建 Redux store,集中管理状态。
  5. 组件:在其他组件中通过 useSelector 和 useDispatch 访问状态和触发动作。

代码实现

1. 定义 stateactions 和 reducer
// src/store/cartSlice.js
import { createSlice } from '@reduxjs/toolkit'; // 使用 Redux Toolkit 简化代码

// 定义初始状态
const initialState = {
  cartItems: [], // 购物车中的商品
};

// 创建 slice,包含 reducer 和 actions
const cartSlice = createSlice({
  name: 'cart', // slice 名称
  initialState, // 初始状态
  reducers: {
    // 添加商品的 reducer
    addItem: (state, action) => {
      const existingItem = state.cartItems.find(item => item.id === action.payload.id);
      if (existingItem) {
        existingItem.quantity += 1; // 如果商品已存在,增加数量
      } else {
        state.cartItems.push({ ...action.payload, quantity: 1 }); // 如果不存在,添加新商品
      }
    },
    // 移除商品的 reducer
    removeItem: (state, action) => {
      state.cartItems = state.cartItems.filter(item => item.id !== action.payload.id);
    },
  },
});

// 导出 actions
export const { addItem, removeItem } = cartSlice.actions;

// 导出 reducer
export default cartSlice.reducer;
2. 创建 store,集中管理状态
// src/store/store.js
import { configureStore } from '@reduxjs/toolkit'; // 使用 Redux Toolkit 简化代码
import cartReducer from './cartSlice'; // 引入 cartReducer

// 创建 store
const store = configureStore({
  reducer: {
    cart: cartReducer, // 将 cartReducer 挂载到 store
  },
});

export default store;
3. 在主应用中使用 Provider 包裹组件
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; // 引入 Provider
import store from './store/store'; // 引入 store
import App from './App';

ReactDOM.render(
  <Provider store={store}> {/* 使用 Provider 包裹应用,传递 store */}
    <App />
  </Provider>,
  document.getElementById('root')
);
4. 创建商品列表组件
// src/components/ProductList.js
import React from 'react';
import { useDispatch } from 'react-redux'; // 引入 useDispatch
import { addItem } from '../store/cartSlice'; // 引入 addItem action

const products = [
  { id: 1, name: '商品 1', price: 10 },
  { id: 2, name: '商品 2', price: 20 },
  { id: 3, name: '商品 3', price: 30 },
];

function ProductList() {
  const dispatch = useDispatch(); // 获取 dispatch 函数

  const handleAddToCart = product => {
    dispatch(addItem(product)); // 触发 addItem action
  };

  return (
    <div>
      <h2>商品列表</h2>
      <ul>
        {products.map(product => (
          <li key={product.id}>
            {product.name} - ¥{product.price}
            <button onClick={() => handleAddToCart(product)}>添加到购物车</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ProductList;
5. 创建购物车组件
// src/components/Cart.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux'; // 引入 useSelector 和 useDispatch
import { removeItem } from '../store/cartSlice'; // 引入 removeItem action

function Cart() {
  const cartItems = useSelector(state => state.cart.cartItems); // 获取购物车商品
  const dispatch = useDispatch(); // 获取 dispatch 函数

  const handleRemoveFromCart = item => {
    dispatch(removeItem(item)); // 触发 removeItem action
  };

  // 计算购物车总价
  const totalPrice = cartItems.reduce((total, item) => total + item.price * item.quantity, 0);

  return (
    <div>
      <h2>购物车</h2>
      {cartItems.length === 0 ? ( // 如果购物车为空,显示提示信息
        <p>购物车为空</p>
      ) : (
        <ul>
          {cartItems.map(item => (
            <li key={item.id}>
              {item.name} - ¥{item.price} x {item.quantity}
              <button onClick={() => handleRemoveFromCart(item)}>移除</button>
            </li>
          ))}
        </ul>
      )}
      <h3>总价: ¥{totalPrice}</h3>
    </div>
  );
}

export default Cart;
6. 主应用组件
// src/App.js
import React from 'react';
import ProductList from './components/ProductList'; // 引入商品列表组件
import Cart from './components/Cart'; // 引入购物车组件

function App() {
  return (
    <div>
      <h1>购物车应用</h1>
      <ProductList />
      <Cart />
    </div>
  );
}

export default App;

 在这个例子中,Redux 中公共管理的状态是定义在 cartSlice.js 中的 initialState,具体是:

const initialState = { cartItems: [], // 购物车中的商品};

  1. cartItems

    • 这是一个数组,用于存储用户添加到购物车中的商品。
    • 每件商品是一个对象,包含以下属性:
      • id:商品的唯一标识。
      • name:商品名称。
      • price:商品价格。
      • quantity:商品的数量。
  2. 全局状态

    • 在 Redux 中,initialState 是这个 slice(模块)的初始状态。
    • 这个状态通过 store.js 挂载到 Redux 的全局状态树中。
    • 其他组件可以通过 useSelector 访问这个状态,也可以通过 useDispatch 触发动作来修改这个状态。

代码解析

  1. cartSlice.js

    • 使用 Redux Toolkit 的 createSlice 定义 statereducer 和 actions
    • addItem:添加商品到购物车,如果商品已存在则增加数量。
    • removeItem:从购物车中移除商品。
  2. store.js

    • 使用 configureStore 创建 Redux store。
    • 将 cartSlice 的 reducer 挂载到 store。
  3. ProductList.js

    • 使用 useDispatch 触发 addItem 动作,将商品添加到购物车。
  4. Cart.js

    • 使用 useSelector 获取购物车中的商品。
    • 使用 useDispatch 触发 removeItem 动作,移除商品。
  5. App.js

    • 展示商品列表和购物车组件。

总结

通过这种方式,我们实现了类似 Vuex 的状态管理结构:

  • state 和 actions 单独抽离,模块化管理。
  • 使用 Redux Toolkit 简化了 Redux 的代码。
  • 在组件中通过 useSelector 和 useDispatch 访问和操作状态。

这种模式非常适合大型应用的状态管理,代码结构清晰,易于维护和扩展。 😊