React+JavaScript中fetch获取API数据JSON解析渲染报错排查
报错根因
你遇到的是典型的类型不匹配+React Hook使用错误,具体问题点:
- 初始状态类型错误:
page.js中存储接口返回值的data初始值设为空对象{},但子组件CustomerListResults的PropTypes明确要求customers为数组类型。组件首次渲染时接口请求尚未返回,传入子组件的是空对象,对象上不存在slice/map/length这类数组原型方法,直接触发customers.slice is not a function运行时错误。 - useEffect缺少依赖项:当前useEffect没有传入第二个依赖数组参数,每次组件重渲染都会重新执行fetch请求,触发无限重渲染循环。
- 遍历逻辑变量引用错误:
list_component.js中map遍历的单个列表项参数是customer,但渲染单元格内容、设置key值时错误引用了整个数组customers的属性,就算数据类型正确也会渲染出错误内容。 - 错误处理逻辑失效:
setError不支持多参数传入,当前错误状态赋值逻辑无法正确保存接口报错信息,且没有捕获fetch请求的网络异常。 - 分页逻辑缺失:slice起始索引固定为0,翻页后列表内容不会更新。
修复代码
修正后的page.js
function Customers(props) { // 初始值设为空数组,匹配子组件的props类型要求 const [data, setData] = useState([]); const [error, setError] = useState(null); useEffect(() => { fetch("http://localhost:8080/contacts") .then((response) => { // 用response.ok覆盖所有2xx成功状态判断,比单独判断status===200更严谨 if (!response.ok) { throw new Error(`Invalid response: ${response.status}`); } return response.json(); }) .then((json) => { // 双重兜底:如果接口返回值不是数组,默认存入空数组避免类型错误 // 注意:如果接口返回结构是{data: [...]}这类包裹格式,这里要取对应数组字段,比如setData(Array.isArray(json.data) ? json.data : []) setData(Array.isArray(json) ? json : []); }) .catch((err) => { // 统一捕获网络错误、接口状态错误存入error状态 setError(err); }); }, []); // 传入空依赖数组,仅在组件首次挂载时执行一次请求 if (error !== null) { return <div>Error: {error.message}</div>; } return ( <DashboardLayout> <> <Head> <title>Data</title> </Head> <Box component="main" sx={{ flexGrow: 1, py: 8 }} > <Container maxWidth={false}> <Box sx={{ mt: 3 }}> <CustomerListResults customers={data} /> </Box> </Container> </Box> </> </DashboardLayout> ); } export default Customers;
修正后的list_component.js遍历逻辑
只需要修改TableBody和TablePagination部分的逻辑即可,其余代码保持不变:
<TableBody> {/* 修正slice起始索引,适配分页切换 */} {customers.slice(page * limit, page * limit + limit).map((customer) => ( <TableRow hover key={customer.id} // 取当前遍历项的唯一标识作为key > <TableCell> <Box sx={{ alignItems: 'center', display: 'flex' }} > <Typography color="textPrimary" variant="body2" > {customer.created_date} {/* 取当前遍历项的属性,而非整个数组 */} </Typography> </Box> </TableCell> <TableCell> {customer.user_idx} {/* 同上,使用单个遍历项变量 */} </TableCell> </TableRow> ))} </TableBody> {/* 分页部分count直接取数组长度即可,无需修改 */} <TablePagination component="div" count={customers.length} onPageChange={handlePageChange} page={page} rowsPerPage={limit} />
注意:如果通过Postman验证接口时发现返回的JSON不是直接的数组结构,不要把整个响应对象直接存入state,必须取到实际存放联系人数组的字段再赋值。
内容的提问来源于stack exchange,提问作者Jaeseo Lee
相关产品推荐
相关产品推荐

