为什么 useState 会在具有不同 props 的路由之间共享?
P粉571233520
P粉571233520 2024-03-30 21:19:56
0
2
494

我有一个应用程序,有两个选项卡“Apple”和“Banana”。每个选项卡都有一个使用 useState 实现的计数器。

const Tab = ({ name, children = [] }) => {
  const id = 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 = 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 = 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 name="Apple" />;
          }}
        />
        <Route
          path="/banana"
          exact={true}
          render={() => {
            return <Tab name="Banana" />;
          }}
        />
      </Switch>
    </Router>
  );
};

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

root.render(<App />);

版本:

  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router": "5.2.1",
    "react-router-dom": "5.2.1",
    "uuid": "^9.0.0"
  },

P粉571233520
P粉571233520

全部回复(2)
P粉496886646

Adam 对这里发生的事情有一个很好的解释和答案,这是一种优化,不会仅仅因为 URL 路径发生变化而拆除并重新安装相同的 React 组件。使用 React 键肯定会解决这个问题,强制 React 重新挂载 Tab 组件,从而“重置”count 状态。

我建议使用另一种方法,当 name 属性从 "apple" 更改为 "banana" 时,保持挂载路由组件并简单地重置 count 状态,反之亦然。

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

  useEffect(() => {
    setCount(0); //  {
    e.preventDefault();
    setCount(c => c + 1);
  };

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

  return (
    

{name} Tab

Render ID: {id}

Counter: {count}

{children}
); };

这将使 RRD 优化为您服务,而不是对您不利。

如果您没有像 name 这样的传递道具可以从中获取提示,则可以使用 location.pathname 。请注意,这确实将一些内部组件逻辑与外部细节耦合起来。

示例:

const { pathname } = useLocation();
const [count, setCount] = useState(0);

useEffect(() => {
  setCount(0);
}, [pathname, setCount]);
P粉608647033

这与Switch 在react-router-dom中工作

最终,即使您切换路由,您的组件树也保持相同。

始终是路由器 -> 交换机 -> 路由 -> 选项卡

由于 Switch 的工作方式,React 永远不会“安装”新组件,它只是重用旧树,因为它可以。

我之前遇到过这个问题,解决方法是在某处添加一个键,例如在 TabRoute 上。我通常将其添加到 Route 因为它在我看来更有意义:


         {
            return ;
          }}
        />
         {
            return ;
          }}
        />
      

检查这个堆栈闪电战:

https://stackblitz.com/edit/react-gj5mcv ?file=src/App.js

当然,当每个选项卡卸载时,您的状态都会在每个选项卡中重置,这可能是也可能不是理想的。但解决这个问题的方法当然是(如果这对你来说是个问题的话),像往常一样,提升状态。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板