React Router报错:Cannot read properties of undefined (reading 'params')求助
解决React Router v6中
props.match.params.id报错的问题 你的核心问题是React Router v6已不再通过组件props传递match对象,旧教程的写法不适用于新版本,因此出现props.match为undefined的报错。以下是具体修复步骤:
1. 导入useParams钩子
从react-router-dom引入v6获取路由参数的标准钩子:
import { Navigate, useParams } from "react-router-dom";
2. 获取并处理路由参数
在组件内部替换原props.match.params.id的写法,同时适配TypeScript类型:
const UserEdit = () => { // 获取路由参数,指定id为字符串类型 const { id } = useParams<{ id: string }>(); // 转换为数字类型(适配后端接口要求) const userId = id ? Number(id) : 0; // ... 其余state定义保持不变
3. 修正数据请求逻辑
在useEffect中改用新获取的userId,并增加空值判断避免无效请求:
useEffect(() => { (async () => { const response = await axios.get('roles'); setRoles(response.data); // 路由参数无效时终止请求 if (!userId) return; const { data } = await axios.get(`users/${userId}`); setFirstName(data.first_name); setLastName(data.last_name); setEmail(data.email); setRoleId(data.role_id.toString()); // 转换为字符串适配select的value类型 })() }, [userId]); // 依赖userId,路由参数变化时自动重新请求数据
4. 修复表单回显问题
你当前使用的defaultValue是非受控组件写法,state更新时输入框不会同步。改为受控组件写法,用value绑定state:
// 示例:First Name输入框修改 <input className="form-control" placeholder="First Name" value={first_name} // 替换defaultValue为value onChange={e => setFirstName(e.target.value)} required /> // Last Name、Email输入框执行同样修改
5. 修正更新请求的URL
更新单个用户通常需要携带id,修正axios.put的请求路径:
await axios.put(`users/${userId}`, { first_name, last_name, email, role_id });
完整修复后的代码
import axios from "axios"; import React, { SyntheticEvent, useEffect, useState } from "react"; import { Navigate, useParams } from "react-router-dom"; import Wrapper from "../../components/Wrapper"; import { Role } from "../../models/role"; const UserEdit = () => { const [first_name, setFirstName] = useState(''); const [last_name, setLastName] = useState(''); const [email, setEmail] = useState(''); const [role_id, setRoleId] = useState(''); const [roles, setRoles] = useState<Role[]>([]); const [redirect, setRedirect] = useState(false); const { id } = useParams<{ id: string }>(); const userId = id ? Number(id) : 0; useEffect(() => { (async () => { const response = await axios.get('roles'); setRoles(response.data); if (!userId) return; const { data } = await axios.get(`users/${userId}`); setFirstName(data.first_name); setLastName(data.last_name); setEmail(data.email); setRoleId(data.role_id.toString()); })() }, [userId]); const submit = async (e: SyntheticEvent) => { e.preventDefault(); if (!userId) return; await axios.put(`users/${userId}`, { first_name, last_name, email, role_id }); setRedirect(true) } if(redirect) { return <Navigate to="/users"/>; } return ( <Wrapper> <form onSubmit={submit}> <h1 className="h3 mb-3 fw-normal">Edit user</h1> <div className="form-floating"> <input className="form-control" placeholder="First Name" value={first_name} onChange={e => setFirstName(e.target.value)} required/> <label htmlFor="floatingInput">First Name</label> </div> <div className="form-floating"> <input className="form-control" placeholder="Last Name" value={last_name} onChange={e => setLastName(e.target.value)} required/> <label htmlFor="floatingInput">Last Name</label> </div> <div className="form-floating"> <input type="email" className="form-control" placeholder="Email Address" value={email} onChange={e => setEmail(e.target.value)} required/> <label htmlFor="floatingInput">Email Address</label> </div> <div className="form-floating"> <select className="form-control" id="floatingRole" placeholder="Role" value={role_id} onChange={e => setRoleId(e.target.value)} required> {roles.map((r: Role) => { return ( <option key={r.id} value={r.id.toString()}>{r.name}</option> ) })} </select> <label htmlFor="floatingRole">Role</label> </div> <button className="w-100 btn btn-lg btn-primary" type="submit">Save</button> </form> </Wrapper> ); }; export default UserEdit;
额外说明
- React Router v6移除了
props.match、props.location等props传递,统一用useParams、useLocation、useNavigate钩子替代 - 受控组件通过
value绑定state,能实时同步数据,更适合表单回显与编辑场景 - 增加空值判断可避免路由参数不存在时的无效请求与报错
内容的提问来源于stack exchange,提问作者Rekhy Zakaria
相关产品推荐
相关产品推荐

