React从Firebase获取待办更新state,页面重载后state为空如何解决?
问题原因
Firebase Realtime Database 的 on('value') 是异步回调方法,你当前代码将 setState 写在了回调外部,执行顺序存在逻辑错误:
- 组件挂载时先声明空数组
data = [] - 注册
value事件监听,此时不会立刻执行回调内的逻辑,需要等待网络请求返回数据 - 立刻使用当前空数组执行
setState,state 被赋值为空数组 - 后续拿到Firebase返回数据后,才会往已被赋值给state的数组中插入数据,但PureComponent依赖引用变化判断是否重渲染,数组引用没有变化的情况下不会触发重新渲染,因此页面始终显示为空。
你在控制台看到的array(0)展开后有内容,是浏览器控制台打印引用类型的特性:打印时存储的是引用地址,你手动展开时数组已经被异步回调填充了数据,不代表执行setState时数组已经有值。
修复方案
调整代码逻辑如下:
- 将
setState移入value事件的回调函数内部,保证拿到Firebase返回数据后才更新state - 每次接收新数据时重新声明空数组组装数据,确保传递给
setState的是新的数组引用,触发PureComponent重新渲染 - 新增组件卸载时的监听移除逻辑,避免内存泄漏
- 给列表渲染项添加
key属性,符合React语法规范
完整修复代码
import React, { PureComponent } from 'react'; import firebase from 'firebase' class Charts extends PureComponent { constructor(props) { super(props); this.state = { data: [] }; this.todoRef = firebase.database().ref('Todo'); } componentDidMount = () => { this.todoRef.on('value', (snapshot) => { const todos = snapshot.val(); const data = []; for (let id in todos) { data.push({ id, ...todos[id] }); } this.setState({ data: data }) }); } componentWillUnmount = () => { this.todoRef.off('value'); } render() { return <div> {this.state.data.map(item => ( <p key={item.id}>{item.name}</p> ))} </div> } } export default Charts;
内容的提问来源于stack exchange,提问作者Tomás Díaz Toro
相关产品推荐
相关产品推荐

