You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 13:03:25