状态管理是指如何高效地管理和共享组件中的状态。React 提供了 useState
和 useReducer
来管理本地状态,而对于全局状态,可以使用 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 (
);
}
function Toolbar({ toggleTheme }) {
return (
);
}
function ThemedButton({ toggleTheme }) {
const theme = React.useContext(ThemeContext);
return (
);
}
代码解析:
ThemeContext.Provider
:提供全局状态 theme
。useContext
:在子组件中获取 theme
状态。toggleTheme
:通过父组件传递回调函数来更新状态。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 (
{
// 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 (
商品列表
{products.map(product => (
-
{product.name} - ¥{product.price}
))}
);
}
export default ProductList;
// 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 (
购物车
{state.cartItems.length === 0 ? ( // 如果购物车为空,显示提示信息
购物车为空
) : (
{state.cartItems.map(item => (
-
{item.name} - ¥{item.price} x {item.quantity}
))}
)}
总价: ¥{totalPrice}
);
}
export default Cart;
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 包裹应用,提供全局状态
购物车应用
);
}
export default App;
CartContext
:
createContext
创建上下文。useReducer
管理状态,定义 ADD_ITEM
和 REMOVE_ITEM
两种动作。CartProvider
包裹整个应用,提供全局状态。ProductList
:
dispatch
触发 ADD_ITEM
动作。Cart
:
dispatch
触发 REMOVE_ITEM
动作。App
:
CartProvider
包裹应用,使全局状态在 ProductList
和 Cart
之间共享。
通过这个例子,我们学习了如何使用 Context API
和 useReducer
管理全局状态:
state
:单独定义全局状态。actions
:定义操作状态的函数。reducer
:处理状态更新逻辑。store
:创建 Redux store,集中管理状态。useSelector
和 useDispatch
访问状态和触发动作。state
、actions
和 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;
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;
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 */}
,
document.getElementById('root')
);
// 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 (
商品列表
{products.map(product => (
-
{product.name} - ¥{product.price}
))}
);
}
export default ProductList;
// 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 (
购物车
{cartItems.length === 0 ? ( // 如果购物车为空,显示提示信息
购物车为空
) : (
{cartItems.map(item => (
-
{item.name} - ¥{item.price} x {item.quantity}
))}
)}
总价: ¥{totalPrice}
);
}
export default Cart;
// src/App.js
import React from 'react';
import ProductList from './components/ProductList'; // 引入商品列表组件
import Cart from './components/Cart'; // 引入购物车组件
function App() {
return (
购物车应用
);
}
export default App;
在这个例子中,Redux 中公共管理的状态是定义在 cartSlice.js
中的 initialState
,具体是:
const initialState = { cartItems: [], // 购物车中的商品};
cartItems
:
id
:商品的唯一标识。name
:商品名称。price
:商品价格。quantity
:商品的数量。全局状态:
initialState
是这个 slice(模块)的初始状态。store.js
挂载到 Redux 的全局状态树中。useSelector
访问这个状态,也可以通过 useDispatch
触发动作来修改这个状态。cartSlice.js
:
createSlice
定义 state
、reducer
和 actions
。addItem
:添加商品到购物车,如果商品已存在则增加数量。removeItem
:从购物车中移除商品。store.js
:
configureStore
创建 Redux store。cartSlice
的 reducer
挂载到 store。ProductList.js
:
useDispatch
触发 addItem
动作,将商品添加到购物车。Cart.js
:
useSelector
获取购物车中的商品。useDispatch
触发 removeItem
动作,移除商品。App.js
:
通过这种方式,我们实现了类似 Vuex 的状态管理结构:
state
和 actions
单独抽离,模块化管理。useSelector
和 useDispatch
访问和操作状态。这种模式非常适合大型应用的状态管理,代码结构清晰,易于维护和扩展。