React/Firebase中如何对querySnapshot的push数据按label升序排序
实现方法
你不需要在push单个元素的时候做排序,等所有文档遍历完成、所有元素都存入临时数组后,统一调用数组的sort方法按label字段排序即可,顺便把你现有Hook里的几个逻辑漏洞一起补全,修正后的完整代码如下:
const useItems = () => { const user = firebase.auth().currentUser; const [items, setItems] = useState([]); useEffect(() => { // 拦截未登录场景,避免读取uid报错 if (!user) return; const userUid = user.uid; // 拉取数据 firebase .firestore() .collection("items") .where("User", "==", userUid) .orderBy("Category", "asc") .get() .then((querySnapshot) => { const options = []; // 遍历组装数据 querySnapshot.forEach((doc) => { const docData = doc.data(); options.push({ value: docData.Name.replace(/\s/g, ''), label: docData.Name, Weight: docData.Weight }); }); // 核心:按label做A-Z升序排序 options.sort((prev, next) => prev.label.localeCompare(next.label)); // 把排序后的结果写入状态 setItems(options); }); // 补全useEffect依赖数组 }, [user]); return items; }
额外说明
- 如果你对按
Category排序没有强需求,更推荐直接把Firestore查询里的orderBy("Category", "asc")替换成orderBy("Name", "asc"),让数据库直接返回按名称A-Z排序的结果,省去前端排序的开销,性能更好。 - 排序用
localeCompare而不是直接比较字符串大小,可以正确处理大小写、特殊字符、非英文字符的排序场景,排序结果更符合A-Z的预期。 - 你原代码里的
unsubscribe变量是多余的:get()是一次性拉取数据的方法,只有用onSnapshot()做实时数据监听时才会返回取消订阅的函数,一次性拉取不需要做卸载时的取消订阅处理。 - 原代码里缺失
options数组定义、setItems状态更新调用、useEffect依赖数组,这些问题在上面的修正代码里都已经补全,直接用就不会有闭包、内存泄漏、状态不更新的问题。
内容的提问来源于stack exchange,提问作者Paul VI
相关产品推荐
相关产品推荐

