
Zustand 的 useStore Hook 不能在顶层调用,但可通过 getState() 和 setState() 方法在工具函数、副作用、API 调用等非组件上下文中安全读写状态。
zustand 的 `usestore` hook 不能在顶层调用,但可通过 `getstate()` 和 `setstate()` 方法在工具函数、副作用、api 调用等非组件上下文中安全读写状态。
Zustand 的核心设计哲学之一是“状态即数据”,其 store 实例本身是可直接操作的独立对象——它不仅支持 Hook 形式(useStore()),更提供了面向普通 JavaScript 环境的底层 API:getState()、setState() 和 subscribe()。这意味着你完全可以在 .ts 工具文件、事件回调、定时器、Axios 拦截器甚至 Web Worker 中与 store 交互,而无需依赖 React 渲染上下文。
✅ 正确做法:使用 getState() 和 setState()
将你的 util.ts 改写为如下方式(关键改动已高亮):
// @/store/useStore.ts
import { create } from 'zustand';
interface Room {
room_no: number;
adult: number;
child: number;
infant: number;
}
interface StoreState {
roomState: Room[];
setRoomState: (rooms: Room[]) => void;
}
const useStore = create<StoreState>((set) => ({
roomState: [],
setRoomState: (rooms) => set({ roomState: rooms }),
}));
export default useStore;// @/utils/util.ts
import useStore from '@/store/useStore';
// ✅ 安全:直接调用 store 方法,不使用 Hook
const utilityFunctions = {
sha512: async (str: string): Promise<string> => {
const buf = await crypto.subtle.digest('SHA-512', new TextEncoder().encode(str));
return Array.from(new Uint8Array(buf))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
},
addRoom: (min_inv: number) => {
const currentState = useStore.getState(); // ? 读取当前 state
if (currentState.roomState.length < min_inv) {
useStore.setState({
roomState: [
...currentState.roomState,
{
room_no: currentState.roomState.length + 1,
adult: 0,
child: 0,
infant: 0,
},
],
});
}
},
// ✅ 更推荐:将 state 更新逻辑封装进 store 内部(提升可维护性)
addRoomSafely: (min_inv: number) => {
useStore.setState((state) => {
if (state.roomState.length >= min_inv) return state;
return {
roomState: [
...state.roomState,
{
room_no: state.roomState.length + 1,
adult: 0,
child: 0,
infant: 0,
},
],
};
});
},
};
export default utilityFunctions;⚠️ 注意事项与最佳实践
- 不要解构 useStore() 返回值到顶层:如 const { roomState, setRoomState } = useStore() 是非法的,会触发 ESLint react-hooks/rules-of-hooks 报错。
- 优先使用 setState(callback) 形式:它接收前一个 state,保证更新基于最新快照(尤其在异步或高频调用场景下避免竞态)。
- 避免在工具函数中长期持有 getState() 返回的引用:Zustand 的 getState() 返回的是当前快照(浅拷贝),不是响应式引用;如需监听变化,请用 subscribe()(适用于非组件逻辑,如日志、分析上报)。
- 类型安全提示:确保 create<StoreState> 的泛型声明完整,TypeScript 将自动推导 getState() 和 setState() 的类型,大幅提升开发体验。
✅ 总结
Zustand 天然支持「脱离 React 组件」的状态管理。只需放弃在工具层调用 Hook 的惯性思维,转而使用 useStore.getState() 读取、useStore.setState() 写入,即可优雅解决跨上下文状态操作问题。这不仅消除了 ESLint 报错,更让状态逻辑真正实现关注点分离——UI 层专注渲染,工具层专注业务,store 本身成为统一、可测试、可复用的状态中枢。










