Angular+NgRx+Firebase登录时NgRx Store报TypeError: Cannot freeze求助
问题原因
NgRx 在开发模式下默认开启状态不可变性校验,会对所有存入 Store 的对象执行递归 Object.freeze 操作,避免状态被意外修改保证不可变性。
而 Firebase 返回的 UserCredential 不是普通纯 JavaScript 对象,它包含内置方法、访问器属性、内部循环引用等宿主对象特性,浏览器原生的 Object.freeze 无法处理这类对象,因此抛出 Cannot freeze 错误。
代码错误点
你直接将 Firebase 返回的原生 UserCredential 对象存入 NgRx Store,违反了 NgRx 要求「状态必须是可序列化的纯数据对象」的规范。你之前手动调用 Object.freeze 能临时生效,是因为 NgRx 内部的冻结逻辑检测到对象已经被冻结就会跳过深层遍历,刚好绕开了不可冻结的内部属性,属于临时规避方案,不符合规范,后续做状态持久化、时间旅行调试都会出现问题。
正确修复方案
不要直接存储完整的 UserCredential 对象,只提取业务需要的纯数据字段,组装成普通对象后再存入 Store,示例如下:
1. 调整 State 定义
// 自定义业务需要的凭证类型,不直接依赖Firebase的类型 export interface UserCredentials { uid: string; email: string | null; displayName: string | null; // 补充其他业务需要的字段 } export interface CoreState { readonly credentials: UserCredentials | null; } export const initialCoreState: CoreState = { credentials: null }
2. 调整 Effect 中的数据转换逻辑
map((userCredential: UserCredential) => { // 提取需要的字段,组装为纯JS对象 const credentials = { uid: userCredential.user.uid, email: userCredential.user.email, displayName: userCredential.user.displayName // 补充其他需要的字段 }; return CoreActions.signInSuccess({ credentials }); })
3. 同步调整 Action 和 Reducer 的对应类型
调整完成后无需手动调用 Object.freeze,也不会再出现冻结错误,同时符合 NgRx 状态可序列化的规范。
内容的提问来源于stack exchange,提问作者user5426760
相关产品推荐
相关产品推荐

