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
相关产品推荐
相关产品推荐

