React Native中如何合并Firestore两个集合数据渲染到FlatList
实现方案
思路说明
Firestore属于非关系型数据库,不支持原生联表查询,所以我们可以先把所有用户信息缓存成uid对应用户数据的映射表,再拿到帖子数据后直接从映射表取对应用户信息合并即可,比逐个查询单条用户信息的请求效率高很多。
完整代码修改
1. 调整State定义
const [loading, setLoading] = useState(true); const [posts, setPosts] = useState([]); // 新增用户映射表,key为用户uid,value存对应用户的name和avatar const [userMap, setUserMap] = useState({});
2. 调整useEffect监听逻辑
useEffect(() => { // 监听users集合,实时更新用户映射表 const userSubscriber = firebase .firestore() .collection("users") .onSnapshot((userSnapshot) => { const tempMap = {}; userSnapshot.forEach((userDoc) => { // 注意:默认users集合的文档id就是用户的uid,和posts里存的uid对应,如果你的存储规则不一样,请改成对应字段 const uid = userDoc.id; tempMap[uid] = { name: userDoc.data().name, avatar: userDoc.data().avatar }; }); setUserMap(tempMap); }); // 监听posts集合,拿到数据后和用户映射表合并 const postSubscriber = firebase .firestore() .collection("posts") .orderBy("timestamp", "desc") .onSnapshot((postSnapshot) => { const tempPosts = []; postSnapshot.forEach((postDoc) => { const postData = postDoc.data(); // 取不到对应用户信息时给默认值,避免渲染报错 const userInfo = userMap[postData.uid] || { name: "匿名用户", avatar: "" }; tempPosts.push({ key: postDoc.id, text: postData.text, timestamp: postData.timestamp, image: { uri: postData.image }, name: userInfo.name, avatar: { uri: userInfo.avatar } }); }); setPosts(tempPosts); setLoading(false); }); // 组件卸载时取消两个监听,避免内存泄漏 return () => { userSubscriber(); postSubscriber(); }; // 把userMap加入依赖项,用户信息更新时自动重新合并帖子数据 }, [userMap]);
3. FlatList组件无需修改
原来的FlatList代码可以直接用,合并后的posts数组已经包含所有需要渲染的字段。
常见问题说明
你之前合并报错大概率是异步请求时序问题:还没拿到users集合数据就已经开始渲染帖子,导致取name/avatar时拿到undefined触发渲染错误。上述方案给用户信息加了兜底默认值,同时用户映射表更新后会自动重新合并帖子数据,避免了时序问题。
内容的提问来源于stack exchange,提问作者Natnicha Chuen
相关产品推荐
相关产品推荐

