React从Firestore取数报filter/map is not function如何解决
报错根因
filter is not function报错和异步逻辑写法无关,核心是list状态初始值设置错误:
你声明list状态时没有传入初始值,useState()默认返回undefined。组件首次渲染时Firestore的onSnapshot监听还没拿到返回数据,就会直接执行LoadBooks()函数,此时对undefined调用数组方法.filter()就会触发类型错误。
从本地JSON导入数据不报错,是因为JSON导入是同步执行的,首次渲染时list就能拿到数组值,不会出现undefined的情况。
修复步骤
- 给list状态设置正确的初始值(空数组)
把状态声明从const [list, setList] = useState();改成const [list, setList] = useState([]);。首次渲染时list是空数组,调用.filter不会报错,等Firestore数据返回后setList触发重渲染,会自动加载真实书籍数据。 - (可选优化)调整过滤逻辑,避免生成无效的undefined数组项
你当前的写法是搜索过滤后直接map,分类不匹配的分支没有返回值,会生成值为undefined的数组项,建议把分类判断也放到过滤逻辑里,减少无效渲染。
修复后完整代码
// Fetch Book to Home Page List const [list, setList] = useState([]); // 初始值改为空数组 useEffect(() => { const unsubscribe = onSnapshot(collection(db, "Books"), (snapshot) => { // 补充把文档id存入数据对象,解决原代码key缺失的问题 setList(snapshot.docs.map((doc) => ({id: doc.id, ...doc.data()}))); }); return unsubscribe; // onSnapshot返回的是取消监听函数,组件卸载时自动清理监听 }, []); //search const [search, setSearch] = useState(""); //Category filter const [filter, setFilter] = useState("all"); function LoadBooks() { // 合并搜索+分类过滤逻辑 return list .filter((val) => { // 匹配搜索关键词 const matchSearch = search === "" ? true : val.title.toLowerCase().includes(search.toLowerCase()); // 匹配分类 const matchCategory = filter === "all" ? true : val.category === filter; return matchSearch && matchCategory; }) .map((item) => <Book key={item.id} {...item} />); } const book = LoadBooks();
补充说明:onSnapshot本身是订阅式实时监听方法,不需要额外加async/await包裹,原代码里的监听逻辑本身没有问题,只需要修正初始值即可解决报错。
内容的提问来源于stack exchange,提问作者Tornike Pirtakhia
相关产品推荐
相关产品推荐

