为何不同Props的路由间会共享useState状态?
问题解决:标签页计数器状态共享的原因与修复
问题原因
当使用React Router切换路由时,如果两个路由渲染的是同一类型的组件(这里都是Tab),React会默认复用组件实例以优化性能。这就导致组件内部的useState状态不会被重置,两个标签页共享了同一个计数器状态。
另外,const id = uuid();直接写在组件函数体中,会在每次组件渲染时生成新的UUID,导致Render ID频繁变化,这也是不符合预期的问题。
修复方案
1. 给Tab组件添加唯一Key,避免实例复用
通过给每个路由渲染的Tab组件添加唯一的key属性,让React识别这是两个独立的组件实例,切换时会销毁旧实例并创建新实例,状态自然不会共享:
<Switch> <Route path="/apple" exact={true} render={() => { return <Tab key="apple-tab" name="Apple" />; }} /> <Route path="/banana" exact={true} render={() => { return <Tab key="banana-tab" name="Banana" />; }} /> </Switch>
2. 稳定UUID的生成
将UUID的生成放到useState中,确保只在组件初始化时生成一次,避免每次渲染都改变:
const Tab = ({ name, children = [] }) => { // 仅组件挂载时生成一次UUID const [id] = useState(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] = useState(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] = useState(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 key="apple-tab" name="Apple" />; }} /> <Route path="/banana" exact={true} render={() => { return <Tab key="banana-tab" name="Banana" />; }} /> </Switch> </Router> ); }; const container = document.getElementById("root"); const root = createRoot(container); root.render(<App />);
内容的提问来源于stack exchange,提问作者sdgfsdh
相关产品推荐
相关产品推荐

