React实现API搜索栏时出现filter读取undefined错误求助
解决React搜索栏API数据过滤的TypeError问题
问题原因拆解
你遇到的TypeError: Cannot read properties of undefined (reading 'filter')以及过滤返回undefined的问题,根源在这几点:
- 错误的过滤目标:
datum是API返回的数组,你错误地尝试调用datum.title?.filter()——数组本身没有title属性,所以datum.title是undefined,自然无法调用filter方法。 - 多余的异步处理:数组过滤是同步操作,你给
handleFilter加了async/await,导致把普通数组当成Promise处理,最终返回undefined。 - 逻辑匹配偏差:原代码遍历元素所有属性做匹配,但实际需求是搜索食品名称,直接检查
title属性更精准高效。
修复步骤与代码调整
1. 修正Filter组件的过滤逻辑
移除不必要的async/await,直接对datum数组进行过滤,同时明确针对title属性做匹配:
import { useState, useMemo } from "react" function Filter({ datum }) { const [filterText, setFilterText] = useState("") const handleInput = (e) => { setFilterText(e.target.value) } // 使用useMemo缓存过滤结果,避免每次渲染重复计算 const filteredData = useMemo(() => { if (!filterText.trim()) return datum const lowerCaseFilter = filterText.toLowerCase() return datum.filter(item => item.title.toLowerCase().includes(lowerCaseFilter) ) }, [datum, filterText]) return ( <div> <input type="text" placeholder="请输入食品名称" onChange={handleInput} value={filterText} /> {/* 渲染过滤后的结果 */} {filteredData.map((el) => ( <div key={el.id} className="items"> <img src={el.image} alt={el.title} /> <p>{el.title}</p> </div> ))} </div> ) } export default Filter
这里用
useMemo缓存过滤结果,只有当datum或filterText变化时才重新计算,提升性能;同时用el.id作为key,比索引更符合React最佳实践。
2. 优化APICall组件的依赖数组与兜底处理
原代码的useEffect依赖数组为空,加上setDatum避免ESLint警告,同时给API返回结果加兜底,确保datum始终是数组:
import axios from "axios" import { useState, useEffect } from 'react' function APICall({ setDatum }) { const [loading, setLoading] = useState(false) useEffect(() => { const fetchAPI = async () => { setLoading(true) try { const res = await axios(`https://api.spoonacular.com/food/products/search?query=yogurt&apiKey=你的API密钥`) setDatum(res.data.products || []) // 兜底空数组,避免API返回异常导致datum为undefined } catch(err) { console.log(err) setDatum([]) // 错误时也设置空数组,防止后续渲染报错 } setLoading(false) } fetchAPI() }, [setDatum]) // 添加setDatum到依赖 if (loading) { return <div>加载中...</div> } return null // 加载完成后不需要显示内容,返回null即可 } export default APICall
3. 可选:统一加载状态管理
如果想在Filter组件也显示加载提示,可以把loading状态提到App组件:
import "../App.css" import APICall from "./APICall.js" import Filter from "./Filter.js" import { useState } from "react" function App() { const [datum, setDatum] = useState([]) const [loading, setLoading] = useState(false) return ( <div className="App"> {loading ? <div>加载中...</div> : <Filter datum={datum} />} <APICall setDatum={setDatum} setLoading={setLoading} /> </div> ) } export default App
然后修改APICall组件,接收setLoading并调用:
// APICall组件内 useEffect(() => { const fetchAPI = async () => { setLoading(true) try { // ...原API逻辑 } catch(err) { // ...错误处理 } setLoading(false) } fetchAPI() }, [setDatum, setLoading])
关键总结
- 始终确保操作的是数组本身,而非数组不存在的属性
- 同步操作不要滥用
async/await,避免把普通值当成Promise处理 - 给状态设置合理的初始值和兜底值,防止数据未加载或加载异常时的报错
- 用
useMemo缓存计算密集的操作,提升组件性能
内容的提问来源于stack exchange,提问作者Recep Çankaya
相关产品推荐
相关产品推荐

