React项目解决useEffect调用API时id为undefined的崩溃问题
问题根源分析
- 父组件跳转未传初始参数:跳转时
<Link>未传递state,导致子组件location.state为undefined,后续赋值逻辑直接出错。 - menuItemId判断逻辑错误:
location.state !== null || location.state !== undefined这个条件永远为true——不管location.state是null还是undefined,总有一个条件成立,会强行执行menuItemId = location.state.menuItemId,直接把menuItemId变成undefined。 - 变量声明方式错误:用普通
let声明menuItemId,不是React状态变量,无法触发组件重新渲染,也没法保证值的稳定性。 - API调用未做合法性校验:直接用可能无效的
menuItemId拼接URL,导致后端返回400错误,甚至引发页面崩溃。 - Comments组件props接收错误:组件定义时没正确接收
props参数,导致取props.menuItemId时抛出异常。
修复方案
1. 父组件传递初始menuItemId
跳转时通过state传递默认的menuItemId(比如初始值0):
<li key={index}> <Link key={index} to='/ChildComponent' state={{ menuItemId: 0 }}>ABC Company</Link> </li>
2. 子组件正确管理menuItemId并校验API调用
改用React状态变量管理menuItemId,修复判断逻辑,并且在API调用前做合法性校验:
import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import axios from 'axios'; const ChildComponent = () => { const location = useLocation(); const [details, setDetails] = useState([]); // 初始化menuItemId:优先取路由state的值,没有则设为0 const [menuItemId, setMenuItemId] = useState(() => { return location.state?.menuItemId ?? 0; }); // 监听左侧菜单点击事件(假设左侧菜单组件点击时触发此回调) const handleMenuItemClick = (id) => setMenuItemId(id); useEffect(() => { // 先校验menuItemId的合法性,避免无效请求 if (menuItemId == null || typeof menuItemId !== 'number') { console.warn('无效的menuItemId,跳过API请求'); return; } const fetchData = async () => { try { const response = await axios.get(`${window.location.origin}/api/displayData/${menuItemId}`); setDetails(response.data); } catch (e) { console.error('获取数据失败:', e); // 可选:添加用户可见的错误提示 // setError('加载数据失败,请稍后重试'); } }; fetchData(); }, [menuItemId]); return ( <> <Row> <Comments menuItemId={menuItemId} /> </Row> {/* 左侧菜单组件,传入点击回调 */} <LeftMenu onItemClick={handleMenuItemClick} /> </> ); }; export default ChildComponent;
3. 修复Comments组件的props接收
确保组件正确接收并使用props:
import React, { useState, useEffect } from 'react'; // 明确接收props参数 const Comments = (props) => { const menuId = props.menuItemId; // 或者用解构赋值更简洁:const { menuItemId: menuId } = props; useEffect(() => { // 同样先校验menuId的合法性 if (menuId == null) return; // 这里写基于menuId的业务逻辑 }, [menuId]); return ( <div> 评论区(对应ID:{menuId}) </div> ); }; export default Comments;
额外优化建议
- 在API请求失败时,不要只打印日志,可以给用户显示友好的错误提示,避免页面崩溃。
- 可以给
menuItemId添加更严格的类型校验,比如typeof menuItemId === 'number' && menuItemId >= 0,确保始终是有效数字。 - 统一管理状态:如果左侧菜单是子组件,通过回调函数将选中的ID传递给父组件(当前的子组件),避免状态分散。
内容的提问来源于stack exchange,提问作者adventureworks
相关产品推荐
相关产品推荐

