React数组元素覆盖问题:添加元素后除新增项外均重复
解决Firestore onSnapshot导致数组元素重复的问题
看起来你遇到的核心问题是Firestore的onSnapshot监听每次触发时,都会往同一个数组里追加数据,最终导致数组元素重复。我来帮你分析下问题根源,再给出修复方案:
问题原因
你的datesArray是在useEffect的作用域内定义的,只初始化一次。但onSnapshot是持续监听数据变化的回调——每次数据库数据更新,这个回调都会执行,而你一直在往同一个datesArray里push新数据,最后设置到state里的自然就是累积了多轮数据的重复数组。之前尝试调用setArray([])没用,是因为清空状态后,下一次快照回调又会把累积的数组重新赋值回去。
修复方案
这里有三个关键修改点:
- 每次快照触发时重新初始化数组:把
datesArray的定义移到onSnapshot回调内部,确保每次数据更新都用全新的数组存储当前快照内容 - 补充useEffect的依赖项:你的查询依赖了
object.id和props.date,必须把它们加入依赖数组,否则这些值变化时,监听的还是旧的查询条件 - 清理Firestore监听:
onSnapshot会返回一个取消订阅的函数,在组件卸载或依赖变化时调用它,避免内存泄漏
修改后的完整代码
const [array, setArray] = useState([]) const [loading, setLoading] = useState(false) useEffect(() => { setLoading(true) const objectRef = firebase.firestore().collection('obiekt').doc(object.id) let startDay = new Date(props.date); let endDay = new Date(props.date); startDay.setHours(0, 0, 0, 0); endDay.setHours(23, 59, 59, 999); // 获取取消订阅函数,用于后续清理 const unsubscribe = firebase.firestore().collection("wydarzenie") .where('obiekt', '==', objectRef) .where('data_rozpoczecia', '>=', startDay) .where('data_rozpoczecia', '<=', endDay) .orderBy('data_rozpoczecia') .onSnapshot(resp => { // 每次快照触发时重新创建空数组,避免累积旧数据 let datesArray = []; resp.docs.forEach(el => { // 这里用forEach比map更合适,因为不需要返回值 datesArray.push({ ...el.data(), id: el.id }) }) setLoading(false) setArray(datesArray) console.log(datesArray) }) // 组件卸载或依赖变化时,取消Firestore监听 return () => unsubscribe() }, [object.id, props.date]) // 补充查询依赖的变量 // 渲染部分 {array && array.map(hour => { return ( <div className={styles.CalendarInfoHour} key={hour.id}> {moment(hour.data_rozpoczecia.toDate()).locale('pl').format('LT')}- {moment(hour.data_zakonczenia.toDate()).locale('pl').format('LT')} Zajęte </div> ) })}
额外优化小提示
把resp.docs.map()改成resp.docs.forEach()会更语义化,因为我们只是遍历文档做push操作,不需要利用map返回的新数组~
内容的提问来源于stack exchange,提问作者poldeeek
相关产品推荐
相关产品推荐

