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

为何不同Props的路由间会共享useState状态?

问题解决:标签页计数器状态共享的原因与修复

问题原因

当使用React Router切换路由时,如果两个路由渲染的是同一类型的组件(这里都是Tab),React会默认复用组件实例以优化性能。这就导致组件内部的useState状态不会被重置,两个标签页共享了同一个计数器状态。

另外,const id = uuid();直接写在组件函数体中,会在每次组件渲染时生成新的UUID,导致Render ID频繁变化,这也是不符合预期的问题。

修复方案

1. 给Tab组件添加唯一Key,避免实例复用

通过给每个路由渲染的Tab组件添加唯一的key属性,让React识别这是两个独立的组件实例,切换时会销毁旧实例并创建新实例,状态自然不会共享:

<Switch>
  <Route
    path="/apple"
    exact={true}
    render={() => {
      return <Tab key="apple-tab" name="Apple" />;
    }}
  />
  <Route
    path="/banana"
    exact={true}
    render={() => {
      return <Tab key="banana-tab" name="Banana" />;
    }}
  />
</Switch>

2. 稳定UUID的生成

将UUID的生成放到useState中,确保只在组件初始化时生成一次,避免每次渲染都改变:

const Tab = ({ name, children = [] }) => {
  // 仅组件挂载时生成一次UUID
  const [id] = useState(uuid());
  const [count, setCount] = useState(0);

  const onClick = e => {
    e.preventDefault();
    setCount(c => c + 1);
  };

  const style = {
    background: "cyan",
    margin: "1em",
  };

  return (
    <section style={style}>
      <h2>{name} Tab</h2>
      <p>Render ID: {id}</p>
      <p>Counter: {count}</p>
      <button onClick={onClick}>+1</button>
      {children}
    </section>
  );
};

完整修改后的代码

import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { v4 as uuid } from "uuid";
import { HashRouter as Router, Switch, Route, Link } from "react-router-dom";

const Tab = ({ name, children = [] }) => {
  const [id] = useState(uuid());
  const [count, setCount] = useState(0);

  const onClick = e => {
    e.preventDefault();
    setCount(c => c + 1);
  };

  const style = {
    background: "cyan",
    margin: "1em",
  };

  return (
    <section style={style}>
      <h2>{name} Tab</h2>
      <p>Render ID: {id}</p>
      <p>Counter: {count}</p>
      <button onClick={onClick}>+1</button>
      {children}
    </section>
  );
};

const App = () => {
  const [id] = useState(uuid());

  return (
    <Router>
      <h1>Hello world</h1>
      <p>Render ID: {id}</p>
      <ul>
        <li>
          <Link to="/apple">Apple</Link>
        </li>
        <li>
          <Link to="/banana">Banana</Link>
        </li>
      </ul>
      <Switch>
        <Route
          path="/apple"
          exact={true}
          render={() => {
            return <Tab key="apple-tab" name="Apple" />;
          }}
        />
        <Route
          path="/banana"
          exact={true}
          render={() => {
            return <Tab key="banana-tab" name="Banana" />;
          }}
        />
      </Switch>
    </Router>
  );
};

const container = document.getElementById("root");
const root = createRoot(container);

root.render(<App />);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 04:07:06