我有一个应用程序,有两个标签“苹果”和“香蕉”。每个标签都有一个计数器,用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>
);
};
令人困惑的是,计数器状态在两个选项卡之间共享!
如果我在一个选项卡上增加计数器,然后切换到另一个选项卡,那里的计数器也会改变。
这是为什么呢?
以下是我的完整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 />);
版本:
"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"
},
2条答案
按热度按时间xkftehaa1#
它与
Switch
在react-router-dom中的工作方式有关最终,组件树保持相同,即使在切换路由时也是如此。
始终是路由器-〉交换机-〉路由-〉选项卡
由于Switch的工作方式,React从不“挂载”新组件,它只是重用旧的树,因为它可以。
我以前遇到过这个问题,解决方法是在某个地方添加一个密钥,比如在
Tab
或Route
上。我通常将其添加到Route
,因为在我看来这更有意义:看看这个stackblitz:
https://stackblitz.com/edit/react-gj5mcv?file=src/App.js
当然,当它们被卸载时,你的状态会在每个选项卡中重置,这可能是可取的,也可能是不可取的。但是解决这个问题的方法当然是(如果这对你来说是个问题的话),像往常一样,提升状态。
7y4bm7vi2#
Adam对这里发生的事情有很好的解释和回答,并且不会因为URL路径改变而拆除并重新挂载相同的React组件是一种优化。使用React密钥肯定会通过***强制***React重新挂载
Tab
组件并因此“重置”count
状态来解决这个问题。我建议另一种方法,保持路由组件安装,并简单地重置
count
状态时,name
prop 从"apple"
到"banana"
,反之亦然。这将使RRD优化为您工作,而不是对您不利。
如果你没有一个像
name
这样的传递属性来作为提示,那么可以使用location.pathname
。注意,这确实将一些内部组件逻辑耦合到外部细节。示例: