Redux 中的 Firebase 用户对象意外嵌套问题解析与解决方案

17次阅读

Redux 中的 Firebase 用户对象意外嵌套问题解析与解决方案

firebase 返回的用户对象并非普通 javascript 对象,而是包含不可枚举属性、原型链和内部私有字段(如 `_z`, `_x`)的特殊类实例;直接存入 redux store 会导致 `mapstatetoprops` 获取到被 proxy 或序列化包装后的非预期结构。

react Native + Firebase + redux 架构中,你遇到的 user 状态被随机包裹在 _z、_x、_y 等键下的现象,并非 Redux 本身的问题,而是 Firebase SDK 返回的对象具有不可序列化的内部结构 —— 它们是 User 类的实例(继承自 FirebaseUser),内部使用了私有字段和 proxy 拦截机制,用于延迟加载或安全封装(例如 getIdToken() 的响应对象也同理)。

当你执行:

props.setUser({   id: user['uid'],   email: user['email'],   token: token });

表面上看你在构造一个普通对象,但若 user[‘uid’] 或 user[’email’] 实际引用的是 Firebase 内部的 getter/Proxy 属性(尤其在某些调试环境或 Hermes 引擎下行为更明显),该对象可能仍携带隐藏原型或不可枚举属性。Redux DevTools 或 react-redux 的 shallowEqual 检测机制在序列化/比较时会触发这些属性的展开,导致 mapStateToProps 接收到的 state.user 实际是一个被深度代理包装的结构(表现为 _z: { _z: { … } } 等嵌套)。

✅ 正确做法:始终将 Firebase 对象“脱水”(hydrate → dehydrate)为纯 jsON 对象

// ✅ 推荐:使用 toPlainObject 或手动解构(更可控) const plainUser = {   id: user.uid,           // 直接访问属性,而非 user['uid']   email: user.email,   displayName: user.displayName ?? null,   photoURL: user.photoURL ?? null,   isAnonymous: user.isAnonymous,   // 注意:token 需单独处理(它本身是 promise 结果,非 Firebase 对象) }; props.setUser(plainUser);

⚠️ 特别注意:auth.currentUser?.getIdToken() 返回的是 Promise,不是 Firebase 对象,无需 .tojson();但如果你错误地将整个 userCredential.user(即 User 实例)直接传入 setUser,就极易触发此问题。

? 进阶建议:在 reducer 中增加防御性校验

case 'SET_USER':   // 强制转换为 plain object,避免 Proxy/Class 实例污染 state   const safePayload = action.payload && typeof action.payload === 'object'     ? JSON.parse(JSON.Stringify(action.payload))     : action.payload;   console.log('Normalized user:', safePayload);   return safePayload;

? 补充说明:.toJSON() 方法在 Firebase User 实例上确实存在(返回一个 plain object),但它并非所有版本都稳定支持,且部分字段(如 metadata)仍可能含 date 实例。因此更稳妥的方式是显式白名单解构,而非依赖 .toJSON()。

? 总结:

  • ❌ 不要将 firebase.User 实例、firebase.auth.UserCredential 等 SDK 类实例直接存入 Redux;
  • ✅ 始终手动提取所需字段,构建 plain object;
  • ✅ 在 mapStateToProps 中无需 hack 如 user._z._z,只需确保 store 中存储的是标准 POJO(Plain Old javaScript Object);
  • ?️ 若需持久化复杂数据,考虑搭配 redux-persist 并配置 stateReconciler 处理反序列化逻辑。

这样即可彻底规避神秘 _z 嵌套,让状态管理回归可预测、可调试、可维护的本质。

text=ZqhQzanResources