React Hooks根据ID查询数据时出现Cannot read property 'params' of undefined错误求助
解决React Hooks中TypeError: Cannot read property 'params' of undefined的问题
看起来你遇到的核心问题是路由参数无法传递到函数组件中——这是因为React Router不会像给类组件那样,自动给函数组件注入match、location这类路由相关的props,尤其是你在App.js里用了<Route>直接包裹组件的写法(<Route exact path="/task/:id"><SingleTask /></Route>),这种情况下组件完全拿不到路由参数。
下面给你两种解决方案,推荐用第一种(Hooks原生方式),更贴合你现在学习React Hooks的场景:
方案1:使用useParams钩子(推荐)
useParams是React Router专门为函数组件提供的钩子,能直接获取URL中的参数,用法非常简洁:
修改你的SingleTask组件:
import React, { useEffect, useState } from 'react'; import axios from 'axios'; import { useParams } from 'react-router-dom'; // 新增导入useParams function SingleTask () { // 初始化状态 const initialTaskState = { _id: "", title: "", created_by: "", description: "", __v: 0 } const [singleTask, setTask] = useState(initialTaskState) const { id } = useParams(); // 直接从URL中提取id参数 // 获取单条任务的请求函数 const fetchSingTask = (taskId) => { // 注意:GET请求不需要额外传id作为第二个参数,URL里已经包含了 axios.get(`/api/tasks/${taskId}`) .then((res) => { setTask(res.data) console.log(res.data) }) .catch (err => { console.log(err) }) } useEffect(() => { // 加个判断,确保id存在时再发起请求,避免空值导致的无效请求 if (id) { fetchSingTask(id) } }, [id]) // 依赖项直接写id即可 return( <div> {/* 加个加载提示,避免初始状态下标题为空的尴尬 */} <h1> {singleTask.title || 'Loading...'} </h1> </div> ) } export default SingleTask;
方案2:使用withRouter高阶组件
如果你还是习惯通过props获取路由参数,可以用withRouter包裹组件,它会把match、location、history这些路由相关的props注入到组件中:
修改SingleTask组件:
import React, { useEffect, useState } from 'react'; import axios from 'axios'; import { withRouter } from 'react-router-dom'; // 新增导入withRouter function SingleTask (props) { // 初始化状态 const initialTaskState = { _id: "", title: "", created_by: "", description: "", __v: 0 } const [singleTask, setTask] = useState(initialTaskState) // 获取单条任务的请求函数 const fetchSingTask = (id) => { axios.get(`/api/tasks/${id}`) // 移除多余的第二个id参数 .then((res) => { setTask(res.data) console.log(res.data) }) .catch (err => { console.log(err) }) } useEffect(() => { // 用可选链操作符`?.`避免props.match为undefined时报错 if (props.match?.params.id) { fetchSingTask(props.match.params.id) } }, [props.match?.params.id]) return( <div> <h1> {singleTask.title || 'Loading...'} </h1> </div> ) } // 用withRouter包裹组件,注入路由相关props export default withRouter(SingleTask);
额外的小提示
- 你的axios GET请求里多传了一个
id参数,GET请求的参数已经包含在URL中了,不需要再作为第二个参数传递,直接去掉即可。 - 在useEffect中添加id存在的判断,可以避免组件初始化时id为空导致的无效请求。
- 渲染标题时加个
Loading...的兜底内容,能提升用户体验,避免初始状态下页面显示空白。
为什么类组件可以正常工作?因为类组件如果直接作为Route的component属性(比如<Route component={SingleTask} />),React Router会自动注入路由相关的props,但函数组件用<Route><SingleTask /></Route>这种写法时,不会自动注入,所以需要用上面两种方法来获取路由参数。
内容的提问来源于stack exchange,提问作者Austin
相关产品推荐
相关产品推荐

