我有一個應用程序,有兩個選項卡“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粉4968866462024-03-31 18:52:50
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); // <-- reset to 0 when name prop updates }, [name, setCount]); const onClick = e => { 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粉6086470332024-03-31 18:42:56
#最終,即使您切換路由,您的元件樹也保持相同。
總是路由器 -> 交換器 -> 路由 -> 選項卡
由於 Switch 的工作方式,React 永遠不會「安裝」新元件,它只是重複使用舊樹,因為它可以。
我之前遇到過這個問題,解決方法是在某處添加一個鍵,例如在 Tab
或 Route
上。我通常將其添加到 Route
因為它在我看來更有意義:
{ return ; }} /> { return ; }} />
檢查這個堆疊閃電戰:
https://stackblitz.com/edit/react-gj5mcv ?file=src/App.js
#當然,當每個選項卡卸載時,您的狀態都會在每個選項卡中重置,這可能是也可能不是理想的。但解決這個問題的方法當然是(如果這對你來說是個問題的話),像往常一樣,提升狀態。