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

React Router+Redux中ownProps为空,读取params时报错求助

问题原因

React Router v6 彻底移除了向路由组件自动传递match、location、history等props的机制,所以你通过connect的mapStateToProps读取ownProps.match时,ownProps是空对象,自然会抛出Cannot read properties of undefined (reading 'params')错误。

解决方案

直接在组件内部使用React Router v6的useParams钩子获取路由参数,结合Redux的useSelector获取状态,替代mapStateToProps中依赖ownProps的逻辑;同时用useNavigate替代旧的history对象。

修改后的AddOrUpdateProduct.js代码

import React, { useEffect, useState, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useParams, useNavigate } from 'react-router-dom'
import { getCategories } from "../../redux/actions/CategoryActions";
import { saveProduct } from "../../redux/actions/ProductActions";
import ProductDetail from "./ProductDetail";

function AddOrUpdateProduct() {
  const { productId } = useParams();
  const navigate = useNavigate();
  const dispatch = useDispatch();
  
  // 从Redux获取状态
  const products = useSelector(state => state.productListReducer);
  const categories = useSelector(state => state.categoryListReducer);
  
  // 根据productId获取对应产品
  const targetProduct = useMemo(() => {
    return productId && products.length > 0 ? getProductById(products, productId) : {};
  }, [productId, products]);

  const [product, setProduct] = useState({ ...targetProduct });
  const [errors, setErrors] = useState({});

  useEffect(() => {
    // 加载分类数据
    if (!categories || categories.length === 0 || !Array.isArray(categories)) {
      dispatch(getCategories());
    }
    // 产品变化时更新状态
    setProduct({ ...targetProduct });
  }, [targetProduct, categories, dispatch]);

  function handleChange(event) {
    const { name, value } = event.target;
    setProduct(previousProduct => ({
      ...previousProduct,
      [name]: name === "categoryId" ? parseInt(value, 10) : value
    }));

    validate(name, value);
  }

  function validate(name, value) {
    if (name === "productName" && value === "") {
      setErrors(previousErrors => ({
        ...previousErrors,
        productName: "Ürün ismi olmalıdır"
      }));
    } else {
      setErrors(previousErrors => ({
        ...previousErrors,
        productName: ""
      }));
    }
  }

  function handleSave(event) {
    event.preventDefault();
    dispatch(saveProduct(product)).then(() => {
      navigate("/");
    });
  }

  return (
    <ProductDetail
      product={product}
      categories={categories}
      onChange={handleChange}
      onSave={handleSave}
      errors={errors}
    />
  );
}

export function getProductById(products, productId) {
  let product = products.find(product => product.id === productId) || null;
  return product;
}

export default AddOrUpdateProduct;

关键修改点

  • 移除connect的mapStateToProps,改用useSelector直接从Redux获取状态
  • 用useParams获取路由参数productId,用useMemo缓存计算后的目标产品
  • 用useNavigate替代history.push实现页面跳转
  • 用useDispatch替代connect的mapDispatchToProps(也可以保留mapDispatchToProps,但hooks写法更贴合React Router v6的风格)

额外说明

如果仍想保留connect来处理dispatch,可以保留mapDispatchToProps,但状态部分还是用useSelector和useParams处理,修改后的导出部分如下:

const mapDispatchToProps = {
  getCategories,
  saveProduct
};

export default connect(null, mapDispatchToProps)(AddOrUpdateProduct);

此时组件的props会包含getCategories和saveProduct,不需要再用useDispatch,直接调用props里的方法即可。

内容的提问来源于stack exchange,提问作者The_Grunt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:53:18