React监听Firestore更新时componentDidUpdate触发无限循环问题求助
问题原因与修复方案
无限循环根本原因
- 引用类型对比失效:
newDat是数组(引用类型),每次请求后你都会创建全新的arr数组赋值给newDat,哪怕数组内部内容完全一致,两个数组的内存地址也不相同,this.state.newDat !== prevState.newDat判断永远为真,每次更新都会触发请求。 - 逻辑闭环错误:你在
componentDidUpdate中监听newDat变化,触发请求后又修改newDat,天然形成「更新newDat→触发componentDidUpdate→请求接口→再次更新newDat」的死循环,和你要的「Firestore更新才同步」的需求完全不匹配。 - 额外代码问题:
componentDidMount中使用的i变量未定义,且console.log(this.state.newDat)后直接调用catch会抛出语法错误(catch只能接在Promise实例后)。
正确实现方案
方案1:使用Firestore官方实时监听(推荐)
Firestore自带实时推送能力,不需要手动轮询判断更新,避免额外性能消耗,示例代码如下:
componentDidMount() { console.log('did mount'); // 监听对应集合的实时变化,只要Firestore数据更新就会触发回调 this.unsubscribe = db.collection('你的集合名').onSnapshot((snapshot) => { const arr = snapshot.docs.map((doc, index) => { return { ['item' + (index + 1)]: { status: doc.data().status } } }) this.setState({ newDat: arr }) }, (e) => console.log(e)) } componentWillUnmount() { // 组件卸载时取消监听,避免内存泄漏 this.unsubscribe && this.unsubscribe() }
方案2:修复现有轮询逻辑,避免死循环
如果你坚持要用axios轮询的方式实现,不要把请求逻辑放在componentDidUpdate中监听newDat变化,改为固定间隔轮询,同时对比数组内容而不是引用判断是否需要更新状态:
componentDidMount() { console.log('did mount'); // 首次拉取数据 this.fetchData() // 每3秒轮询一次,可自行调整间隔 this.pollTimer = setInterval(() => { this.fetchData() }, 3000) } componentWillUnmount() { // 组件卸载清除定时器 clearInterval(this.pollTimer) } // 封装数据拉取逻辑 fetchData = () => { axios.get(url).then(r => { const newArr = [] for (let i = 0; i < r.data.documents.length; i++) { newArr.push({ ['item' + (i + 1)]: { status: r.data.documents[i].fields.status.stringValue, }, }) } // 深对比数组内容,只有真实发生变化才更新state if (JSON.stringify(this.state.newDat) !== JSON.stringify(newArr)) { this.setState({ newDat: newArr }) } }).catch(e => console.log(e)) }
内容的提问来源于stack exchange,提问作者Carlos Correa
相关产品推荐
相关产品推荐

