為什麼 useState 會在具有不同 props 的路由之間共用?
P粉571233520
P粉571233520 2024-03-30 21:19:56
0
2
394

我有一個應用程序,有兩個選項卡“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

#當然,當每個選項卡卸載時,您的狀態都會在每個選項卡中重置,這可能是也可能不是理想的。但解決這個問題的方法當然是(如果這對你來說是個問題的話),像往常一樣,提升狀態。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!