React项目中如何向Firestore的array字段追加map元素不覆盖原有值
解决方案
问题根因
- 初始实现直接将
recipeDb字段赋值为仅包含当前点击食谱的单元素数组,调用update时会直接覆盖该字段的原有内容,因此无法实现追加效果 - 后续使用
FieldValue.arrayUnion时存在3处错误:arrayUnion要求传入待追加的单个元素,你传入了包着食谱对象的数组,会导致嵌套数组插入- 字段名不匹配,原有存储字段为
recipeDb,测试代码错误使用了fav作为字段名 - 每次点击都注册
onAuthStateChanged监听器,会导致重复触发逻辑、内存泄漏
修正后实现
import { useEffect, useState } from 'react'; const RecipeCard = () => { // 存储当前登录用户状态,避免每次点击重复注册auth监听器 const [currentUser, setCurrentUser] = useState(null); // 组件挂载时仅注册一次auth状态监听 useEffect(() => { const unsubscribe = fire.auth().onAuthStateChanged((user) => { setCurrentUser(user); }); // 组件卸载时注销监听器,清理内存 return unsubscribe; }, []); const dbFavorites = () => { // 未登录状态直接终止逻辑 if (!currentUser) return; // 生成单个食谱对象,不需要包入数组 const newRecipe = { Recipe: title, Id: id, Source: source, }; const userFavoritesRef = fire .firestore() .collection(`User-favorites${currentUser.uid}`) .doc(currentUser.uid); // 先尝试update追加元素 userFavoritesRef .update({ recipeDb: fire.firestore.FieldValue.arrayUnion(newRecipe), }) .catch((err) => { // 首次收藏时文档不存在,用set初始化数组 if (err.code === 'not-found') { userFavoritesRef.set({ recipeDb: [newRecipe], }); } }); }; return ( <button type="button" onClick={dbFavorites}> 收藏食谱 </button> ); };
额外说明
arrayUnion会自动对元素去重,只要待插入的食谱对象和数组内已有对象字段完全匹配,就不会重复插入,符合收藏功能的常规需求- 如果你使用的是Firebase v9+模块化版本,
arrayUnion的写法需要调整为从firebase/firestore导入后直接调用:import { arrayUnion, doc, updateDoc, setDoc } from 'firebase/firestore'; // 调用时写法 updateDoc(userFavoritesRef, { recipeDb: arrayUnion(newRecipe) })
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

