ReactJS:使用firestoreConnect从Props存对象到State遇异常求助
解决React-Redux-Firebase加载Firestore设备数据的问题
看起来你遇到的核心问题是异步数据加载的时机处理不当,以及初始渲染时auth.uid未就绪导致的Firestore查询无效。咱们一步步拆解解决:
问题根源分析
- Auth数据加载延迟:组件初始化时,
props.auth.uid可能还未从Firebase Auth加载完成,导致firestoreConnect中的查询条件无效,无法获取到devices数据。 - 异步数据未做加载判断:直接访问
devices的属性(比如name)时,数据可能还在加载中,此时devices是undefined或空数组,自然会抛出"Can't read property 'name' of undefined"错误。 - 不必要的State同步:在
componentDidMount中把props.devices存入state是冗余操作,redux的props是响应式的,存到state反而会导致数据不同步。
具体修复方案
1. 修复Firestore查询条件,确保Auth就绪后再发起查询
修改firestoreConnect,只有当auth.uid存在时才发起查询,避免无效请求:
firestoreConnect((props) => { // 仅当用户已登录(uid存在)时,才查询对应设备 return props.auth.uid ? [ { collection: 'devices', where: [ ['managerId', '==', props.auth.uid] ] } ] : []; })
2. 移除冗余的State同步逻辑
删掉componentDidMount中的setState操作,直接使用props中的devices即可,redux会自动同步数据更新:
// 删掉这段代码 componentDidMount() { this.setState({ dev: this.props.devices }) }
3. 渲染时添加数据加载判断
在render方法中先检查devices是否存在且有数据,再进行渲染,避免报错:
render() { const {devices, profile, classes, className, ...rest } = this.props; const rootClassName = classNames(classes.root, className); // 判断设备数据是否加载完成 const hasLoadedDevices = devices && devices.length > 0; return ( <Paper {...rest} className={rootClassName} > <div className={classes.content}> <div className={classes.details}> <Typography className={classes.title} variant="body2" > Device </Typography> {/* 根据加载状态显示不同内容 */} <Typography className={classes.value} variant="h3" > {hasLoadedDevices ? devices[0].name : 'Loading devices...'} </Typography> </div> <div className={classes.iconWrapper}> <MoneyIcon className={classes.icon} /> </div> </div> <div className={classes.footer}> {hasLoadedDevices ? ( // 遍历设备状态 devices.map(device => ( <Typography key={device.id} className={device.isError ? classes.deviceError : classes.deviceOk} variant="body2" > {device.isError ? <Error /> : <Done />} {device.isError ? 'Error' : 'Running'} </Typography> )) ) : ( <Typography variant="body2">Loading device status...</Typography> )} </div> </Paper> ); }
4. 额外检查:确认Store配置正确
确保你的redux store已经正确集成了redux-firestore和react-redux-firebase,示例配置如下:
import { createStore, combineReducers, compose } from 'redux'; import { reactReduxFirebase, firebaseReducer } from 'react-redux-firebase'; import { reduxFirestore, firestoreReducer } from 'redux-firestore'; import firebase from 'firebase/app'; import 'firebase/firestore'; import 'firebase/auth'; // 你的Firebase配置 const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", // ...其他配置 }; firebase.initializeApp(firebaseConfig); // React-Redux-Firebase配置 const rrfConfig = { userProfile: 'users', useFirestoreForProfile: true // 若用Firestore存储用户信息需开启 }; // 合并reducers const rootReducer = combineReducers({ firebase: firebaseReducer, firestore: firestoreReducer, // ...你的其他reducers }); // 创建带Firebase的store const createStoreWithFirebase = compose( reactReduxFirebase(firebase, rrfConfig), reduxFirestore(firebase) )(createStore); const store = createStoreWithFirebase(rootReducer); export default store;
核心逻辑说明
- 当用户登录完成后,
props.auth.uid会被更新,此时firestoreConnect会自动重新计算查询条件,发起正确的Firestore请求获取设备数据。 - 直接使用props中的
devices,redux会在数据更新时自动触发组件重新渲染,无需手动同步到state。 - 添加加载状态判断,避免在数据未就绪时访问undefined的属性。
内容的提问来源于stack exchange,提问作者Kemal Aydeniz
相关产品推荐
相关产品推荐

