Warum wird useState von Routen mit unterschiedlichen Requisiten gemeinsam genutzt?
P粉571233520
P粉571233520 2024-03-30 21:19:56
0
2
491

Ich habe eine App mit zwei Tabs „Apple“ und „Banane“. Jede Registerkarte verfügt über einen Zähler, der mit useState implementiert wurde.

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>
  );
};

Verwirrenderweise ist der Zählerstand auf beide Registerkarten verteilt!

Wenn ich den Zähler auf einer Registerkarte erhöhe und dann zu einer anderen Registerkarte wechsle, ändert sich auch der Zähler.

Warum ist das so?


Das ist meine komplette App:

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 />);

Version:

  "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

Antworte allen(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

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

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage