如何在Zustand状态中存储带方法的对象并访问其方法?
从Zustand状态获取对象后无法访问其方法,如何正确存储带方法的对象?
问题场景
将Firebase Auth返回的User对象存入Zustand状态后,无法访问其原型方法(如updateEmail),相关代码如下:
Store定义(store.jsx)
import create from "zustand"; import { persist } from "zustand/middleware"; import { cloneDeep } from "lodash"; const initialState = { user: undefined, profile: undefined, } let store = (set) => ({ ...initialState, setUser: (user) => set((state) => ({ user: cloneDeep(user) })), setProfile: (profile) => set((state) => ({ profile: profile })), logout: () => {set(initialState)}, }); store = persist(store); export const useUserStore = create(store);
设置状态(file2.jsx)
import { useUserStore } from "../../store"; const setUser = useUserStore((state) => state.setUser); useEffect(() => { const unsubscribe = auth.onAuthStateChanged((user) => { // 此时user包含所有属性和方法 setUser(user); }); return () => unsubscribe(); }, []);
访问状态(file2.jsx)
import { useUserStore } from "../../../store/userStore"; const user = useUserStore((state) => state.user); // 报错:updateEmail方法未定义 user.updateEmail()
问题原因
核心问题出在cloneDeep(user):Lodash的cloneDeep仅能复制对象的可枚举属性,无法保留对象的原型链及原型上的方法。Firebase User是带原型方法的实例,经过深度克隆后原型链被切断,自然访问不到updateEmail这类方法。另外,若使用了persist中间件,持久化时的JSON序列化也会丢失函数和原型信息。
解决方案
方案1:直接存储原始对象(非持久化场景)
去掉cloneDeep,直接存入原始User实例:
// 修改store中的setUser方法 setUser: (user) => set((state) => ({ user })),
注意:此方案仅适用于不需要持久化的场景,因为persist中间件的JSON序列化会丢失方法。
方案2:拆分存储属性与方法调用(持久化场景)
如果需要持久化用户信息,只存储可序列化的核心属性,调用方法时直接使用Firebase Auth的currentUser:
// 修改setUser,仅存储需要的属性 setUser: (user) => set((state) => ({ user: { uid: user.uid, email: user.email, displayName: user.displayName // 按需添加其他可序列化属性 } })), // 调用方法时直接使用auth.currentUser auth.currentUser.updateEmail(newEmail);
方案3:直接使用Firebase Auth的currentUser
无需将User存入Zustand,直接通过auth.currentUser访问实例及所有方法,避免状态存储带来的原型链丢失问题。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

