Appearance
状态管理最佳实践
概述
无论选择哪种状态管理方案,都有一些通用的最佳实践可以帮助构建更加健壮、可维护、高性能的React应用。本文总结了状态管理的通用最佳实践和各种方案的特定实践。
通用设计原则
1. 单一数据源原则
保持数据的唯一来源,避免状态重复:
jsx
// ❌ 错误:多处维护相同数据
const UserProfile = () => {
const [user, setUser] = useState(null);
// ...
};
const UserSettings = () => {
const [user, setUser] = useState(null); // 重复状态
// ...
};
// ✅ 正确:单一数据源
const userAtom = atom(null);
const UserProfile = () => {
const user = useAtomValue(userAtom);
// ...
};
const UserSettings = () => {
const user = useAtomValue(userAtom); // 共享状态
// ...
};
// Redux版本
const userSlice = createSlice({
name: 'user',
initialState: null,
reducers: {
setUser: (state, action) => action.payload
}
});
// 所有组件都从store获取用户数据
const UserComponent = () => {
const user = useSelector(state => state.user);
// ...
};2. 状态最小化原则
只在全局状态中存储真正需要共享的数据:
jsx
// ❌ 错误:所有状态都放全局
const appState = proxy({
user: null,
posts: [],
// 不应该全局化的状态
currentPage: 1, // 应该在分页组件内部
searchInputValue: '', // 应该在搜索组件内部
modalOpen: false, // 应该在模态框组件内部
tempFormData: {} // 应该在表单组件内部
});
// ✅ 正确:只存储需要共享的状态
const appState = proxy({
user: null, // 多个组件需要
posts: [], // 多个组件需要
theme: 'light' // 全局主题
});
// 组件内部状态
function SearchComponent() {
const [query, setQuery] = useState(''); // 仅本组件需要
const [results, setResults] = useState([]);
// ...
}
function PaginationComponent() {
const [currentPage, setCurrentPage] = useState(1); // 仅本组件需要
// ...
}3. 不可变性原则
确保状态更新是不可变的(除非使用Valtio等可变方案):
jsx
// ❌ 错误:直接修改状态
const badReducer = (state, action) => {
state.count++; // 直接修改
state.items.push(action.payload); // 直接修改数组
return state;
};
// ✅ 正确:返回新对象
const goodReducer = (state, action) => {
return {
...state,
count: state.count + 1,
items: [...state.items, action.payload]
};
};
// Redux Toolkit with Immer
const slice = createSlice({
name: 'example',
initialState: { count: 0, items: [] },
reducers: {
increment: (state) => {
state.count += 1; // Immer处理不可变性
},
addItem: (state, action) => {
state.items.push(action.payload); // Immer处理不可变性
}
}
});
// Zustand with Immer
const useStore = create(
immer((set) => ({
count: 0,
items: [],
increment: () => set((state) => {
state.count += 1;
}),
addItem: (item) => set((state) => {
state.items.push(item);
})
}))
);4. 关注点分离原则
将不同类型的状态分离管理:
jsx
// ✅ 按功能域分离
// 用户相关状态
const useAuthStore = create((set) => ({
user: null,
token: null,
login: async (credentials) => {
const { user, token } = await authAPI.login(credentials);
set({ user, token });
},
logout: () => set({ user: null, token: null })
}));
// UI状态
const useUIStore = create((set) => ({
theme: 'light',
sidebarOpen: false,
notifications: [],
setTheme: (theme) => set({ theme }),
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
addNotification: (notification) => set((state) => ({
notifications: [...state.notifications, notification]
}))
}));
// 业务数据状态
const useDataStore = create((set) => ({
products: [],
orders: [],
cart: [],
fetchProducts: async () => {
const products = await productsAPI.getAll();
set({ products });
}
}));
// Jotai版本 - 原子化分离
const userAtom = atom(null);
const themeAtom = atom('light');
const productsAtom = atom([]);
const cartAtom = atom([]);性能最佳实践
1. 避免不必要的重渲染
jsx
// ❌ 错误:选择整个状态对象
function BadComponent() {
const state = useStore(); // 任何状态变化都会重渲染
return <div>{state.user.name}</div>;
}
// ✅ 正确:精确选择需要的数据
function GoodComponent() {
const userName = useStore((state) => state.user.name);
return <div>{userName}</div>;
}
// Context优化
const UserContext = createContext();
const UIContext = createContext();
// 拆分Context避免无关更新
function App() {
return (
<UserProvider>
<UIProvider>
<MainApp />
</UIProvider>
</UserProvider>
);
}
// 使用React.memo优化
const ExpensiveComponent = React.memo(({ data }) => {
return <ComplexVisualization data={data} />;
});
// Valtio自动优化
function ValtioComponent() {
const snap = useSnapshot(state);
// 只有使用的字段变化才会重渲染
return <div>{snap.user.name}</div>;
}2. 合理使用缓存
jsx
// 使用useMemo缓存计算结果
function DataVisualization() {
const rawData = useStore((state) => state.data);
const filters = useStore((state) => state.filters);
const processedData = useMemo(() => {
return expensiveDataProcessing(rawData, filters);
}, [rawData, filters]);
return <Chart data={processedData} />;
}
// Jotai中使用派生atoms
const rawDataAtom = atom([]);
const filtersAtom = atom({});
const processedDataAtom = atom((get) => {
const rawData = get(rawDataAtom);
const filters = get(filtersAtom);
return expensiveDataProcessing(rawData, filters); // 自动缓存
});
// Redux使用Reselect
import { createSelector } from '@reduxjs/toolkit';
const selectRawData = (state) => state.data.raw;
const selectFilters = (state) => state.filters;
const selectProcessedData = createSelector(
[selectRawData, selectFilters],
(rawData, filters) => expensiveDataProcessing(rawData, filters)
);3. 异步操作优化
jsx
// 批量异步操作
async function batchFetchUserData(userIds) {
const requests = userIds.map(id => fetch(`/api/users/${id}`));
const responses = await Promise.all(requests);
const users = await Promise.all(responses.map(r => r.json()));
// 批量更新状态
setUsers(users);
}
// 使用React Query优化数据获取
function useOptimizedUserData(userId) {
return useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
staleTime: 5 * 60 * 1000, // 5分钟内不重新获取
cacheTime: 10 * 60 * 1000, // 缓存10分钟
refetchOnWindowFocus: false
});
}
// 预加载策略
function useDataPrefetching() {
const queryClient = useQueryClient();
const prefetchUserData = (userId) => {
queryClient.prefetchQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId)
});
};
return { prefetchUserData };
}
// Jotai异步atoms
const userFamily = atomFamily({
key: 'user',
default: async (userId) => {
const response = await fetch(`/api/users/${userId}`);
return response.json();
}
});
// 条件性异步调用
const conditionalDataAtom = atom(async (get) => {
const shouldFetch = get(shouldFetchDataAtom);
if (!shouldFetch) return null;
const response = await fetch('/api/data');
return response.json();
});架构最佳实践
1. 分层架构
jsx
// 三层架构:Presentation -> Business -> Data
// 数据层 (Data Layer)
class UserService {
async getUsers() {
const response = await fetch('/api/users');
return response.json();
}
async createUser(userData) {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(userData)
});
return response.json();
}
}
// 业务逻辑层 (Business Layer)
const useUserBusiness = () => {
const userService = useUserService();
const setUsers = useSetAtom(usersAtom);
const setLoading = useSetAtom(loadingAtom);
const loadUsers = async () => {
setLoading(true);
try {
const users = await userService.getUsers();
setUsers(users);
} catch (error) {
console.error('Failed to load users:', error);
} finally {
setLoading(false);
}
};
const createUser = async (userData) => {
try {
const newUser = await userService.createUser(userData);
setUsers(prev => [...prev, newUser]);
return newUser;
} catch (error) {
throw new Error('Failed to create user');
}
};
return { loadUsers, createUser };
};
// 表现层 (Presentation Layer)
function UserList() {
const users = useAtomValue(usersAtom);
const loading = useAtomValue(loadingAtom);
const { loadUsers, createUser } = useUserBusiness();
useEffect(() => {
loadUsers();
}, []);
if (loading) return <LoadingSpinner />;
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
<CreateUserForm onCreate={createUser} />
</div>
);
}2. 状态标准化
jsx
// ❌ 错误:嵌套的非标准化数据
const badState = {
posts: [
{
id: 1,
title: 'Post 1',
author: { id: 1, name: 'Alice', email: 'alice@example.com' },
comments: [
{ id: 1, text: 'Comment 1', author: { id: 2, name: 'Bob' } },
{ id: 2, text: 'Comment 2', author: { id: 1, name: 'Alice', email: 'alice@example.com' } }
]
}
]
};
// ✅ 正确:标准化的扁平结构
const goodState = {
entities: {
users: {
1: { id: 1, name: 'Alice', email: 'alice@example.com' },
2: { id: 2, name: 'Bob', email: 'bob@example.com' }
},
posts: {
1: { id: 1, title: 'Post 1', authorId: 1, commentIds: [1, 2] }
},
comments: {
1: { id: 1, text: 'Comment 1', authorId: 2, postId: 1 },
2: { id: 2, text: 'Comment 2', authorId: 1, postId: 1 }
}
},
ui: {
selectedPostId: null,
loading: false
}
};
// Redux Toolkit Entity Adapter
const usersAdapter = createEntityAdapter();
const postsAdapter = createEntityAdapter();
const commentsAdapter = createEntityAdapter();
const usersSlice = createSlice({
name: 'users',
initialState: usersAdapter.getInitialState(),
reducers: {
userAdded: usersAdapter.addOne,
userUpdated: usersAdapter.updateOne,
usersLoaded: usersAdapter.setAll
}
});
// Jotai版本
const usersAtom = atom({});
const postsAtom = atom({});
const commentsAtom = atom({});
// 辅助selectors
const userByIdFamily = atomFamily({
key: 'userById',
default: (userId) => atom((get) => get(usersAtom)[userId])
});
const postWithDetailsFamily = atomFamily({
key: 'postWithDetails',
default: (postId) => atom((get) => {
const posts = get(postsAtom);
const users = get(usersAtom);
const comments = get(commentsAtom);
const post = posts[postId];
if (!post) return null;
return {
...post,
author: users[post.authorId],
comments: post.commentIds.map(id => ({
...comments[id],
author: users[comments[id].authorId]
}))
};
})
});3. 关注点分离
jsx
// 按功能领域分离状态管理逻辑
// auth/authStore.js - 认证相关
export const useAuthStore = create((set) => ({
user: null,
token: null,
login: async (credentials) => {
const response = await authAPI.login(credentials);
set({ user: response.user, token: response.token });
},
logout: () => set({ user: null, token: null })
}));
// products/productsStore.js - 产品相关
export const useProductsStore = create((set) => ({
products: [],
selectedProduct: null,
filters: {},
fetchProducts: async () => {
const products = await productsAPI.getAll();
set({ products });
},
setFilters: (filters) => set({ filters }),
selectProduct: (product) => set({ selectedProduct: product })
}));
// ui/uiStore.js - UI状态
export const useUIStore = create((set) => ({
theme: 'light',
sidebarOpen: false,
notifications: [],
setTheme: (theme) => set({ theme }),
toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })),
addNotification: (notification) => set((state) => ({
notifications: [...state.notifications, {
id: Date.now(),
...notification,
timestamp: new Date().toISOString()
}]
})),
removeNotification: (id) => set((state) => ({
notifications: state.notifications.filter(n => n.id !== id)
}))
}));数据流最佳实践
1. 单向数据流
jsx
// 保持清晰的数据流向:UI事件 -> Actions -> State -> UI更新
// ❌ 错误:组件直接修改全局状态
function BadComponent() {
const { data, setData } = useStore();
// 直接在组件中修改复杂逻辑
const handleComplexOperation = () => {
// 复杂的业务逻辑混在组件中
const processed = complexProcessing(data);
setData(processed);
updateOtherData(processed);
triggerSideEffects();
};
return <button onClick={handleComplexOperation}>Process</button>;
}
// ✅ 正确:通过actions处理业务逻辑
function GoodComponent() {
const data = useStore((state) => state.data);
const processData = useStore((state) => state.processData);
return <button onClick={processData}>Process</button>;
}
const useStore = create((set, get) => ({
data: [],
processData: async () => {
const currentData = get().data;
// 业务逻辑封装在store中
const processed = await complexProcessing(currentData);
set({ data: processed });
// 相关的副作用
await updateOtherSystems(processed);
triggerAnalytics('data_processed');
}
}));2. 异步操作标准化
jsx
// 标准化的异步操作模式
const createAsyncSlice = (name, apiCall) => {
return createSlice({
name,
initialState: {
data: null,
loading: false,
error: null,
lastFetch: null
},
reducers: {},
extraReducers: (builder) => {
const asyncThunk = createAsyncThunk(
`${name}/fetch`,
apiCall
);
builder
.addCase(asyncThunk.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(asyncThunk.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
state.lastFetch = Date.now();
})
.addCase(asyncThunk.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
return { ...createSlice, asyncThunk };
}
});
};
// 使用
const usersSlice = createAsyncSlice('users', () =>
fetch('/api/users').then(r => r.json())
);
// Zustand版本
const createAsyncStore = (fetcher) => create((set) => ({
data: null,
loading: false,
error: null,
fetch: async () => {
set({ loading: true, error: null });
try {
const data = await fetcher();
set({ data, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
}
}));
// Jotai版本
const createAsyncAtom = (key, fetcher) => {
const dataAtom = atom(async () => {
return await fetcher();
});
const loadableAtom = loadable(dataAtom);
return loadableAtom;
};3. 错误处理标准化
jsx
// 全局错误处理
const errorHandlingStore = create((set) => ({
errors: [],
addError: (error) => set((state) => ({
errors: [...state.errors, {
id: Date.now(),
message: error.message,
type: error.type || 'error',
timestamp: new Date().toISOString(),
stack: error.stack
}]
})),
removeError: (id) => set((state) => ({
errors: state.errors.filter(e => e.id !== id)
})),
clearErrors: () => set({ errors: [] })
}));
// 统一的错误处理Hook
function useErrorHandler() {
const addError = useStore((state) => state.addError);
const handleAsyncError = (asyncFn) => async (...args) => {
try {
return await asyncFn(...args);
} catch (error) {
addError({
message: error.message,
type: 'api_error',
context: { fn: asyncFn.name, args }
});
throw error;
}
};
return { handleAsyncError };
}
// 使用错误处理
function UserService() {
const { handleAsyncError } = useErrorHandler();
const fetchUsers = handleAsyncError(async () => {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Failed to fetch users');
return response.json();
});
return { fetchUsers };
}代码组织最佳实践
1. 文件结构
src/
├── stores/ # 状态管理
│ ├── auth/
│ │ ├── authStore.js
│ │ ├── authTypes.js
│ │ └── authSelectors.js
│ ├── products/
│ │ ├── productsStore.js
│ │ └── productsSelectors.js
│ └── index.js # 导出所有stores
│
├── hooks/ # 自定义hooks
│ ├── useAuth.js
│ ├── useProducts.js
│ └── useAPI.js
│
├── services/ # API服务
│ ├── authAPI.js
│ ├── productsAPI.js
│ └── baseAPI.js
│
└── utils/ # 工具函数
├── stateUtils.js
└── validation.js2. 命名约定
jsx
// Store命名
const useUserStore = create(...); // use + 领域 + Store
const useProductsStore = create(...);
const useUIStore = create(...);
// Action命名 - 动词开头
const actions = {
// 数据操作
fetchUsers: () => {},
createUser: () => {},
updateUser: () => {},
deleteUser: () => {},
// UI操作
openModal: () => {},
closeModal: () => {},
setTheme: () => {},
toggleSidebar: () => {},
// 业务操作
processOrder: () => {},
calculateDiscount: () => {},
validateForm: () => {}
};
// Atom命名
const userAtom = atom(null); // 数据atom
const isLoadingAtom = atom(false); // 状态atom
const userFormAtom = atom({}); // 表单atom
// Selector命名
const filteredUsersAtom = atom((get) => {}); // 派生atom
const userStatsAtom = atom((get) => {}); // 计算atom3. 类型定义
typescript
// 集中的类型定义
// types/index.ts
export interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
createdAt: string;
}
export interface Product {
id: number;
name: string;
price: number;
category: string;
inStock: boolean;
}
export interface CartItem {
id: string;
productId: number;
quantity: number;
options: Record<string, any>;
}
// Store类型
export interface UserStore {
users: User[];
currentUser: User | null;
loading: boolean;
error: string | null;
fetchUsers: () => Promise<void>;
setCurrentUser: (user: User) => void;
updateUser: (id: number, updates: Partial<User>) => void;
}
// 使用泛型创建可复用的store类型
export interface AsyncState<T> {
data: T | null;
loading: boolean;
error: string | null;
lastFetch: number | null;
}
export interface EntityStore<T> extends AsyncState<T[]> {
selectedId: number | null;
filters: Record<string, any>;
}测试最佳实践
1. Store测试
jsx
// Zustand store测试
import { act, renderHook } from '@testing-library/react';
describe('useUserStore', () => {
beforeEach(() => {
useUserStore.setState({ users: [], loading: false, error: null });
});
it('should add user', () => {
const { result } = renderHook(() => useUserStore());
act(() => {
result.current.addUser({ id: 1, name: 'John' });
});
expect(result.current.users).toHaveLength(1);
expect(result.current.users[0].name).toBe('John');
});
it('should handle async operations', async () => {
// Mock API
jest.spyOn(userAPI, 'fetchUsers').mockResolvedValue([
{ id: 1, name: 'John' }
]);
const { result } = renderHook(() => useUserStore());
await act(async () => {
await result.current.fetchUsers();
});
expect(result.current.users).toHaveLength(1);
expect(result.current.loading).toBe(false);
});
});
// Jotai atoms测试
describe('userAtom', () => {
it('should store user data', () => {
const { result } = renderHook(() => useAtom(userAtom));
act(() => {
result.current[1]({ id: 1, name: 'John' });
});
expect(result.current[0]).toEqual({ id: 1, name: 'John' });
});
});
// Redux slice测试
describe('userSlice', () => {
it('should handle user creation', () => {
const initialState = { users: [] };
const action = { type: 'users/userAdded', payload: { id: 1, name: 'John' } };
const newState = userSlice.reducer(initialState, action);
expect(newState.users).toHaveLength(1);
});
});2. 组件集成测试
jsx
// 测试组件与状态的集成
import { render, screen, fireEvent } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
function TestWrapper({ children }) {
return (
<RecoilRoot>
{children}
</RecoilRoot>
);
}
describe('UserList component', () => {
it('should display users from store', () => {
const { result } = renderHook(() => useUserStore());
act(() => {
result.current.addUser({ id: 1, name: 'John' });
});
render(<UserList />, { wrapper: TestWrapper });
expect(screen.getByText('John')).toBeInTheDocument();
});
it('should handle user interaction', () => {
render(<UserList />, { wrapper: TestWrapper });
const addButton = screen.getByRole('button', { name: 'Add User' });
fireEvent.click(addButton);
// 验证状态变化
expect(screen.getByText('User added')).toBeInTheDocument();
});
});性能监控和调试
1. 性能监控
jsx
// 性能监控Hook
function usePerformanceMonitor(componentName) {
const renderCount = useRef(0);
const startTime = useRef(performance.now());
useEffect(() => {
renderCount.current++;
const endTime = performance.now();
console.log(`[${componentName}] Render #${renderCount.current}, Duration: ${endTime - startTime.current}ms`);
startTime.current = endTime;
});
}
// 状态变化监控
const useStateChangeMonitor = (store, storeName) => {
useEffect(() => {
const unsubscribe = store.subscribe((state, prevState) => {
const changes = {};
Object.keys(state).forEach(key => {
if (state[key] !== prevState[key]) {
changes[key] = { from: prevState[key], to: state[key] };
}
});
if (Object.keys(changes).length > 0) {
console.log(`[${storeName}] State changes:`, changes);
}
});
return unsubscribe;
}, []);
};
// 使用
function MonitoredComponent() {
usePerformanceMonitor('UserList');
useStateChangeMonitor(useUserStore, 'UserStore');
// 组件逻辑
}2. 调试工具
jsx
// 开发环境调试助手
const createDebugStore = (storeCreator, name) => {
if (process.env.NODE_ENV === 'development') {
return create(
devtools(
subscribeWithSelector(storeCreator),
{ name }
)
);
}
return create(storeCreator);
};
// 状态快照工具
const createStateSnapshot = () => {
const stores = {
user: useUserStore.getState(),
products: useProductsStore.getState(),
ui: useUIStore.getState()
};
return {
timestamp: new Date().toISOString(),
stores,
export: () => JSON.stringify(stores, null, 2),
import: (snapshotJson) => {
const snapshot = JSON.parse(snapshotJson);
useUserStore.setState(snapshot.user);
useProductsStore.setState(snapshot.products);
useUIStore.setState(snapshot.ui);
}
};
};
// 使用
function DebugPanel() {
const [snapshot, setSnapshot] = useState(null);
const handleExport = () => {
const snap = createStateSnapshot();
setSnapshot(snap);
console.log('State exported:', snap.export());
};
return (
<div>
<button onClick={handleExport}>Export State</button>
{snapshot && (
<textarea value={snapshot.export()} readOnly />
)}
</div>
);
}安全最佳实践
1. 敏感数据处理
jsx
// ❌ 错误:敏感数据直接存储在状态中
const badAuthStore = create((set) => ({
user: null,
password: '', // 不应该存储密码
creditCard: '', // 不应该存储信用卡信息
socialSecurityNumber: '' // 不应该存储敏感信息
}));
// ✅ 正确:只存储必要的用户信息
const goodAuthStore = create((set) => ({
user: {
id: null,
email: null,
name: null,
role: null,
// 不存储敏感信息
},
token: null, // JWT token(应该设置过期时间)
// 登录时不存储密码
login: async (email, password) => {
const response = await authAPI.login(email, password);
// password 不会被存储
set({
user: response.user,
token: response.token
});
}
}));
// 敏感操作的处理
const secureOperations = {
// 支付操作:不存储支付信息
processPayment: async (paymentDetails) => {
// 直接传递给支付服务,不存储在状态中
return await paymentService.process(paymentDetails);
},
// 敏感信息更新:立即清除
updateSensitiveInfo: async (info) => {
try {
await userAPI.updateSensitive(info);
// 成功后立即清除本地引用
info = null;
} catch (error) {
// 错误时也要清除
info = null;
throw error;
}
}
};2. 输入验证和清理
jsx
// 输入验证中间件
const validationMiddleware = (config) => (set, get, api) => {
return config(
(partial, replace, action) => {
// 验证输入数据
if (typeof partial === 'object' && partial !== null) {
const validatedData = validateAndSanitize(partial);
set(validatedData, replace, action);
} else {
set(partial, replace, action);
}
},
get,
api
);
};
function validateAndSanitize(data) {
const sanitized = {};
Object.entries(data).forEach(([key, value]) => {
if (typeof value === 'string') {
// XSS防护:清理HTML标签
sanitized[key] = value.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
} else {
sanitized[key] = value;
}
});
return sanitized;
}
// 使用验证中间件
const useSecureStore = create(
validationMiddleware((set) => ({
userInput: '',
setUserInput: (input) => set({ userInput: input })
}))
);可维护性最佳实践
1. 文档和注释
jsx
/**
* 用户认证Store
* 管理用户登录状态、个人信息和权限
*
* @example
* const { user, login, logout } = useAuthStore();
*
* if (user) {
* // 用户已登录
* }
*/
const useAuthStore = create((set, get) => ({
/**
* 当前登录用户信息
* @type {User | null}
*/
user: null,
/**
* 认证token
* @type {string | null}
*/
token: null,
/**
* 用户登录
* @param {Object} credentials - 登录凭据
* @param {string} credentials.email - 邮箱
* @param {string} credentials.password - 密码
* @returns {Promise<User>} 返回用户信息
* @throws {Error} 登录失败时抛出错误
*/
login: async (credentials) => {
const response = await authAPI.login(credentials);
set({ user: response.user, token: response.token });
return response.user;
},
/**
* 用户登出
* 清除用户信息和token,并通知服务器
* @returns {Promise<void>}
*/
logout: async () => {
await authAPI.logout();
set({ user: null, token: null });
},
/**
* 检查用户是否有特定权限
* @param {string} permission - 权限名称
* @returns {boolean} 是否有权限
*/
hasPermission: (permission) => {
const { user } = get();
return user?.permissions?.includes(permission) || false;
}
}));2. 代码复用
jsx
// 创建可复用的store模式
function createCRUDStore(entityName, apiService) {
return create((set, get) => ({
// 标准CRUD状态
items: [],
selectedItem: null,
loading: false,
error: null,
// 标准CRUD操作
fetchItems: async () => {
set({ loading: true, error: null });
try {
const items = await apiService.getAll();
set({ items, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
createItem: async (itemData) => {
const newItem = await apiService.create(itemData);
set((state) => ({
items: [...state.items, newItem]
}));
return newItem;
},
updateItem: async (id, updates) => {
const updatedItem = await apiService.update(id, updates);
set((state) => ({
items: state.items.map(item =>
item.id === id ? updatedItem : item
)
}));
return updatedItem;
},
deleteItem: async (id) => {
await apiService.delete(id);
set((state) => ({
items: state.items.filter(item => item.id !== id),
selectedItem: state.selectedItem?.id === id ? null : state.selectedItem
}));
},
selectItem: (item) => set({ selectedItem: item }),
clearSelection: () => set({ selectedItem: null })
}));
}
// 使用
const useUsersStore = createCRUDStore('user', userAPI);
const useProductsStore = createCRUDStore('product', productAPI);
const useOrdersStore = createCRUDStore('order', orderAPI);3. 配置和环境管理
jsx
// 环境相关的store配置
const createStoreWithConfig = (storeCreator) => {
const isDevelopment = process.env.NODE_ENV === 'development';
const enableDevtools = isDevelopment && window.__REDUX_DEVTOOLS_EXTENSION__;
let store = storeCreator;
// 开发环境增强
if (isDevelopment) {
if (enableDevtools) {
store = devtools(store, { name: 'AppStore' });
}
// 添加日志
store = subscribeWithSelector(store);
// 性能监控
store = (...args) => {
const result = storeCreator(...args);
// 监控状态变化
result.subscribe((state, prevState) => {
console.group('State Change');
console.log('Previous:', prevState);
console.log('Current:', state);
console.groupEnd();
});
return result;
};
}
return create(store);
};
// 配置驱动的store
const config = {
enablePersistence: true,
enableDevtools: process.env.NODE_ENV === 'development',
enableAnalytics: process.env.NODE_ENV === 'production',
cacheTimeout: 5 * 60 * 1000 // 5分钟
};
const useConfigurableStore = create(
config.enablePersistence
? persist(storeCreator, { name: 'app-store' })
: storeCreator
);团队协作最佳实践
1. 代码审查标准
jsx
// 状态管理代码审查清单
const codeReviewChecklist = [
// 设计层面
'□ 状态结构合理,避免深度嵌套',
'□ 遵循单一数据源原则',
'□ 状态最小化,只存储必要信息',
'□ 关注点正确分离',
// 实现层面
'□ 使用不可变更新(除Valtio外)',
'□ 异步操作正确处理loading/error状态',
'□ Actions命名清晰描述其作用',
'□ 适当使用缓存和性能优化',
// 质量层面
'□ 添加必要的注释和文档',
'□ 类型定义完整(TypeScript项目)',
'□ 错误处理完善',
'□ 测试覆盖关键逻辑',
// 安全层面
'□ 不存储敏感信息在状态中',
'□ 输入验证和清理',
'□ 权限检查到位'
];2. 团队规范
jsx
// 团队开发规范示例
const teamGuidelines = {
// Store命名
naming: {
stores: 'use + 功能域 + Store (如: useUserStore)',
atoms: '功能 + Atom (如: userAtom)',
selectors: '描述性名称 + Selector (如: filteredUsersSelector)',
actions: '动词开头 (如: fetchUsers, updateUser)'
},
// 文件组织
structure: {
smallProject: 'stores/index.js - 所有stores在一个文件',
mediumProject: 'stores/按功能域分文件',
largeProject: 'features/各功能模块包含自己的状态'
},
// 状态设计
stateDesign: [
'优先使用原生类型而不是复杂对象',
'避免在状态中存储派生数据',
'合理拆分状态粒度',
'考虑状态的生命周期'
],
// 性能要求
performance: [
'使用精确的selectors避免不必要渲染',
'大量数据使用虚拟化',
'合理使用React.memo',
'避免在render中创建对象/函数'
]
};
// 团队培训材料
const trainingMaterials = {
// 新员工培训
onboarding: [
'状态管理基础概念',
'项目使用的具体方案',
'团队代码规范',
'调试工具使用',
'常见问题和解决方案'
],
// 进阶培训
advanced: [
'性能优化技巧',
'复杂状态设计模式',
'测试策略',
'架构设计原则'
]
};3. 版本控制和迁移
jsx
// 状态schema版本控制
const stateVersioning = {
version: '1.2.0',
migrations: {
'1.0.0': (oldState) => oldState,
'1.1.0': (oldState) => ({
...oldState,
user: {
...oldState.user,
preferences: oldState.user.settings // 重命名字段
}
}),
'1.2.0': (oldState) => ({
...oldState,
ui: {
...oldState.ui,
theme: oldState.ui.darkMode ? 'dark' : 'light' // 重构主题系统
}
})
},
migrate: (persistedState, currentVersion) => {
let state = persistedState;
Object.keys(migrations).forEach(version => {
if (compareVersions(version, persistedState.version) > 0 &&
compareVersions(version, currentVersion) <= 0) {
state = migrations[version](state);
}
});
return { ...state, version: currentVersion };
}
};
// 在persist中间件中使用
const useVersionedStore = create(
persist(
storeCreator,
{
name: 'app-store',
version: stateVersioning.version,
migrate: stateVersioning.migrate
}
)
);总结
状态管理最佳实践的核心原则:
设计原则
- 单一数据源:避免状态重复
- 状态最小化:只存储必要的全局状态
- 不可变性:确保状态更新的可预测性
- 关注点分离:按功能域组织状态
性能原则
- 精确订阅:避免不必要的重渲染
- 合理缓存:使用memo缓存计算结果
- 异步优化:标准化异步操作模式
- 监控调试:建立性能监控机制
质量原则
- 类型安全:使用TypeScript确保类型正确
- 错误处理:建立统一的错误处理机制
- 测试覆盖:为状态逻辑编写测试
- 文档完善:为复杂逻辑添加文档
团队原则
- 规范统一:建立团队代码标准
- 知识分享:定期技术分享和review
- 渐进迁移:制定合理的技术迁移计划
- 持续改进:定期评估和优化状态管理方案
遵循这些最佳实践,无论使用哪种状态管理库,都能构建出高质量的React应用。