如何在React函数组件外访问Zustand Store?解决Hook调用报错
问题原因
你触发了React Hook的规则限制:React Hook必须在React函数组件或自定义React Hook的顶层调用,不能直接在普通工具文件的顶层、对象或普通函数里调用useStore(它本质是一个React Hook),所以ESLint报错了。
解决方法
以下三种方案可实现需求,根据你的使用场景选择:
方案一:将工具函数封装为自定义Hook
把工具函数改成自定义Hook(命名以use开头),这样就能合法调用useStore,且直接关联store状态,不用手动传参。
修改util.ts:
import useStore from "@/store/useStore"; // 自定义Hook,符合React Hook规则 const useUtilityFunctions = () => { const { roomState, setRoomState } = useStore(); const sha512 = (str: string) => { return crypto.subtle.digest("SHA-512", new TextEncoder().encode(str)).then(buf => { return Array.prototype.map.call(new Uint8Array(buf), x => (('00' + x.toString(16)).slice(-2))).join(''); }); }; const addRoom = (min_inv: number) => { if (roomState.length < min_inv) { setRoomState([ ...roomState, { room_no: roomState.length + 1, adult: 0, child: 0, infant: 0, }, ]); } }; return { sha512, addRoom }; }; export default useUtilityFunctions;
组件内使用:
import useUtilityFunctions from '@/utils/util'; const MyComponent = () => { const { sha512, addRoom } = useUtilityFunctions(); const handleAddRoom = () => addRoom(3); return <button onClick={handleAddRoom}>添加房间</button>; };
方案二:直接访问Zustand Store实例
Zustand支持直接访问store原始实例,无需通过Hook,适合在非组件环境(如工具函数、异步逻辑)中调用。
第一步:修改store文件(store/useStore.ts)
导出store实例:
import { create } from 'zustand'; // 创建store实例 const store = create((set) => ({ roomState: [], setRoomState: (newState) => set({ roomState: newState }), // 其他状态/方法... })); // 导出供组件使用的Hook export default store; // 导出供工具函数使用的实例 export const storeInstance = store;
第二步:修改util.ts
直接通过实例获取和修改状态:
import { storeInstance } from "@/store/useStore"; const utililtyFunctions = { sha512: (str: string) => { return crypto.subtle.digest("SHA-512", new TextEncoder().encode(str)).then(buf => { return Array.prototype.map.call(new Uint8Array(buf), x => (('00' + x.toString(16)).slice(-2))).join(''); }); }, addRoom: (min_inv: number) => { const roomState = storeInstance.getState().roomState; if (roomState.length < min_inv) { storeInstance.setState({ roomState: [ ...roomState, { room_no: roomState.length + 1, adult: 0, child: 0, infant: 0, }, ] }); } }, }; export default utililtyFunctions;
调用方式不变,直接导入工具函数即可使用。
方案三:将状态和方法作为参数传入
让工具函数完全与store解耦,调用时手动传入roomState和setRoomState,适合需要适配不同状态来源的场景。
修改util.ts:
const utililtyFunctions = { sha512: (str: string) => { return crypto.subtle.digest("SHA-512", new TextEncoder().encode(str)).then(buf => { return Array.prototype.map.call(new Uint8Array(buf), x => (('00' + x.toString(16)).slice(-2))).join(''); }); }, addRoom: ( roomState: { room_no: number; adult: number; child: number; infant: number }[], setRoomState: (newState: typeof roomState) => void, min_inv: number ) => { if (roomState.length < min_inv) { setRoomState([ ...roomState, { room_no: roomState.length + 1, adult: 0, child: 0, infant: 0, }, ]); } }, }; export default utililtyFunctions;
组件内使用:
import useStore from '@/store/useStore'; import utililtyFunctions from '@/utils/util'; const MyComponent = () => { const { roomState, setRoomState } = useStore(); const handleAddRoom = () => { utililtyFunctions.addRoom(roomState, setRoomState, 3); }; return <button onClick={handleAddRoom}>添加房间</button>; };
内容的提问来源于stack exchange,提问作者Ashutosh Dash
相关产品推荐
相关产品推荐

