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

React中通过Link传递多状态时为何获取到null?

问题:React Router Link传递包含函数的对象时State为null

问题现象

使用react-router-dom的Link组件传递包含item数据和handleCartClick函数的对象myData作为state到子组件ProductDetails时,接收方的location.state为null;但仅传递单个item数据时功能完全正常。

相关验证场景:

  • 单状态传递的代码:仅传递item作为state的Link组件代码
  • 单状态传递的输出:location.state正常包含item数据的控制台输出
  • 多状态传递的代码:传递包含item和handleCartClick的对象作为state的Link组件代码
  • 多状态传递的输出:location.state显示为null的控制台输出

原因分析

React Router在通过Link的state属性传递数据时,会对数据进行序列化处理(类似JSON.stringify逻辑)。而函数无法被JSON序列化,当你在myData中包含handleCartClick函数时,整个state的序列化过程失败,最终导致传递的state变为null。

解决方案

方案1:避免通过路由State传递函数

函数属于逻辑范畴,不适合通过路由state传递。建议只传递item数据,在子组件中通过全局状态管理(如React Context、Redux)或组件上下文获取handleCartClick函数。

修改父组件代码(仅传递item)

// TopCards 父组件
import React from 'react'
import { Link } from 'react-router-dom';
import "../HomePage/TopPicks.css";

const TopCards = ({item,id,handleCartClick}) => {
  const {title,image,price,desc,rating} = item

  const toIndian = (number)=>{
    let x=number.toString();
    let lastThree = x.substring(x.length-3);
    let otherNumbers = x.substring(0,x.length-3);
    if(otherNumbers != '')
        lastThree = ',' + lastThree;
    let res = otherNumbers.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + lastThree;
    return res;
  }

  // 仅传递item数据
  const myData = {
    item: item,
  };

  return (
    <div className="col-sm-3 mb-3 mb-sm-0 topPicks_cards ">
      <Link to='product-details' state={myData}>
        <div className="card topPicks_card" style={{width: "286px"}}>
          <img src= {image} className="card-img-top" alt="..." />
          <div className="card-body">
            <h6 className="card-title">{title}</h6>
            <p className="card-text">{`Rs. ${toIndian(price*80)}`}</p>
            <div className="rating">{rating.rate}</div>
          </div>
        </div>
      </Link>
    </div>
  )
}

export default TopCards

通过React Context共享handleCartClick

  1. 创建CartContext文件:
// CartContext.js
import { createContext, useContext } from 'react';

const CartContext = createContext();

export const CartProvider = ({ children, handleCartClick }) => {
  return (
    <CartContext.Provider value={{ handleCartClick }}>
      {children}
    </CartContext.Provider>
  );
};

export const useCart = () => useContext(CartContext);
  1. 在根组件包裹CartProvider:
// App.js
import { CartProvider } from './CartContext';
import { handleCartClick } from './your-path'; // 导入你的handleCartClick函数
import { BrowserRouter as Router } from 'react-router-dom';

function App() {
  return (
    <Router>
      <CartProvider handleCartClick={handleCartClick}>
        {/* 路由配置和其他组件 */}
      </CartProvider>
    </Router>
  );
}
  1. 在子组件中使用Context:
// ProductDetails子组件
import React,{useState} from 'react'
import { useLocation } from 'react-router-dom'
import { useCart } from '../CartContext';
import Navbar from '../HomePage/Navbar'
import '../ProductDetails/productDetails.css'
import Footer from "../HomePage/Footer"

const ProductDetails = () => {
  const location = useLocation()
  const { handleCartClick } = useCart();
  const state = location.state;
  
  // 增加空值检查,避免直接访问路由时报错
  if (!state?.item) {
    return <div>无效的产品链接</div>;
  }

  const [count, setCount] = useState(0);

  const handleDecrement = ()=>{
    setCount(preValue => preValue < 1 ? 0 : preValue - 1)
  }

  const handleIncrement = ()=>{
    setCount(preValue => preValue + 1)
  }

  const toIndian = (number)=>{
    let x=number.toString();
    let lastThree = x.substring(x.length-3);
    let otherNumbers = x.substring(0,x.length-3);
    if(otherNumbers !== '')
        lastThree = ',' + lastThree;
    let res = otherNumbers.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + lastThree;
    return res;
  }

  // 调用共享的handleCartClick
  const handleAddToCart = () => {
    handleCartClick(state.item);
  }

  return (
    <div className='product-details'>
      <Navbar/>
      <div className="container">
        <div className="product-detail">
          <div className="product-image">
            <img src={state.item.image} alt={state.item.title} />
          </div>
          <div className="product-info">
            <div className="product-title">
              <h3>{state.item.title}</h3>
            </div>
            <div className="desciption">{state.item.description}</div>
            <div className="rating">{state.item.rating.rate}</div>
            <div className="product-price">
              <h3>Rs. {toIndian(state.item.price*80)}</h3>
            </div>
            <div className="counter">
              <span>
                <button type="button" className="btn btn-light" onClick={handleDecrement}>-</button>
              </span>
              <span>
                <button type="button" className="btn btn-light">{count}</button>
              </span>
              <span>
                <button type="button" className="btn btn-light" onClick={handleIncrement}>+</button>
              </span>
              <div className="buying">
                <div className="buy">
                  <button type="button" className="btn btn-primary btn-lg">Buy Now</button>
                </div>
                <div className="addtocart">
                  <button type="button" className="btn btn-primary btn-lg" onClick={handleAddToCart}>Add to Cart</button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <Footer></Footer>
    </div>
  )
}

export default ProductDetails

额外优化:强制空值检查

无论采用哪种方案,都必须在子组件中对location.state进行空值检查,避免用户直接输入路由地址时出现报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:58:10