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

如何向react-router-dom的navigate状态传递类实例?

问题:React Router navigate传递含私有成员的类实例后变为空对象

我尝试通过react-router-dom的navigate方法的state参数,传递一个包含私有成员的类实例,但在消费组件中获取到的是一个空对象,无法访问类的getter方法。

待传递的Cart类:

class Cart{
  #contents;
  add(itemName){
    const existingEntry = this.#contents[itemName];
    const oldCount = existingEntry?.count;
    const newCount = oldCount+1;
    this.#contents[itemName] = {name: itemName, count: newCount};
    return this;
  }
  get contents(){
    return JSON.parse(JSON.stringify(this.#contents))
  }
}

传递实例的组件代码:

function SomeComponent(){
  // 其他React代码...
  const navigate = useNavigate();

  const handleClick = () => {
    const item = 'Bananas';
    const cart = new Cart().add(item); 
    navigate('/someURL', { state: {cart} });
  }
  // 其他React代码...   
}

消费组件代码:

function ConsumerComponent(){
  // 其他React代码...
  const { state } = useLocation();
  console.log(state.cart);  // 输出 '{}'

  // 其他React代码...
}

补充说明(编辑1)

奇怪的是,这段代码在在线沙箱中能正常运行,消费组件可以获取到完整的类实例;但下载到本地运行时,消费组件只能拿到普通空对象。我认同“路由状态仅能传递JSON/字符串可序列化对象”的观点,但无法理解沙箱与本地运行的行为差异,希望得到相关推测或解释。

需求背景

我想实现类似亚马逊“立即购买”的功能:点击按钮时创建一次性使用的Cart实例,导航到/checkout页面时将该实例传入路由状态,不想将Cart存入全局状态管理系统。


解决方案

核心原因

React Router的路由状态依赖浏览器history API,而history状态会被浏览器做JSON序列化处理。私有类字段(#contents)无法被JSON序列化捕获,类实例的方法、getter也不会被序列化,因此传递后会丢失类的特性,变成空对象。

沙箱与本地的行为差异,大概率是沙箱运行环境对history状态做了非标准的优化(比如跳过了严格序列化),但这种特殊行为不能作为生产环境的依赖。

可行方案

方案1:传递序列化数据,消费端重构类实例

将Cart实例的可公开数据序列化后传递,在接收组件中重新创建实例并恢复数据:

  1. 给Cart类添加构造函数和静态重构方法:
class Cart{
  #contents;
  // 添加构造函数支持初始数据传入
  constructor(initialContents = {}){
    this.#contents = initialContents;
  }
  add(itemName){
    const existingEntry = this.#contents[itemName];
    const oldCount = existingEntry?.count ?? 0; // 处理初始为空的情况
    const newCount = oldCount + 1;
    this.#contents[itemName] = {name: itemName, count: newCount};
    return this;
  }
  get contents(){
    return JSON.parse(JSON.stringify(this.#contents));
  }
  // 静态方法:从数据重构Cart实例
  static fromData(data){
    return new Cart(data);
  }
}
  1. 传递时只传序列化后的内容:
const handleClick = () => {
  const item = 'Bananas';
  const cart = new Cart().add(item); 
  navigate('/someURL', { state: {cartData: cart.contents} });
}
  1. 消费组件中重构实例:
function ConsumerComponent(){
  const { state } = useLocation();
  const cart = Cart.fromData(state.cartData);
  console.log(cart.contents); // 正常获取内容
}

方案2:内存临时存储(适配一次性场景)

如果不想序列化,可以用全局内存变量临时存储Cart实例,仅传递实例标识,消费组件通过标识获取实例:

  1. 新建临时存储模块(比如tempStore.js):
const tempStore = new Map();
let idCounter = 0;

export const saveTempInstance = (instance) => {
  const id = `cart_${idCounter++}`;
  tempStore.set(id, instance);
  // 可选:设置超时自动清理,避免内存泄漏
  setTimeout(() => tempStore.delete(id), 5 * 60 * 1000);
  return id;
};

export const getTempInstance = (id) => {
  const instance = tempStore.get(id);
  tempStore.delete(id); // 一次性使用后删除
  return instance;
};
  1. 传递组件中存储实例并传递ID:
import { saveTempInstance } from './tempStore';

const handleClick = () => {
  const item = 'Bananas';
  const cart = new Cart().add(item); 
  const cartId = saveTempInstance(cart);
  navigate('/someURL', { state: {cartId} });
}
  1. 消费组件中获取实例:
import { getTempInstance } from './tempStore';

function ConsumerComponent(){
  const { state } = useLocation();
  const cart = getTempInstance(state.cartId);
  console.log(cart.contents); // 正常访问类实例
}

这个方案适配你的“一次性使用”需求,既不会污染全局状态,又能保留类实例的完整特性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 23:39:15