为何独立配置的Private/Protected路由仍共享同一状态?
问题:React Router 私有路由包装器状态未隔离的原因及解决方法
我将私有路由拆分后,为每个路由配置了独立的<PrivateWrapper>组件,但切换路由时状态未实现隔离:在Home路由点击按钮将count增至1后,切换到About路由点击按钮,count会直接变为2。期望两个路由能拥有各自独立的状态,如同普通组件多次调用时的状态隔离效果,请问为何会出现这种情况?
现有代码
App.jsx
function App() { return ( <div> <BrowserRouter> <Routes> <Route element={<PrivateWrapper />} > <Route path="/" element={<Home />} /> </Route> <Route element={<PrivateWrapper />} > <Route path="/about" element={<About />} /> </Route> </Routes> </BrowserRouter> </div> ) } export default App
PrivateWrapper.jsx
function PrivateWrapper() { const [count, setCount] = useState(0) console.log(count) return ( <> <Link to="/">Home</Link> <Link to="/about">About</Link> <Outlet context={{ count, setCount }} /> </> ) } export default PrivateWrapper
About.jsx
function About() { const { setCount } = useOutletContext() return ( <div> <h1>About</h1> <button onClick={() => setCount(prev => prev + 1)}>increment</button> </div> ) } export default About
Home.jsx
function Home() { const { setCount } = useOutletContext() return ( <div> <h1>Home</h1> <button onClick={() => setCount(prev => prev + 1)}>increment</button> </div> ) } export default Home
原因分析
React Router 的 <Routes> 组件会复用匹配的父路由组件实例,而非每次路由切换都创建新的组件实例。虽然你在两个路由中都声明了 <PrivateWrapper />,但当路由在/和/about之间切换时,React Router 识别到两个路由的父组件类型一致,就会复用同一个PrivateWrapper实例,导致状态被共享,无法实现隔离。
解决方法
要让每个路由拥有独立的PrivateWrapper实例,需要让 React 识别它们为不同的组件,以下是两种常用方案:
方案1:为每个PrivateWrapper添加唯一key属性
通过给父路由的element中的PrivateWrapper设置不同的key,让 React 判定为不同的组件实例,从而分别维护状态:
function App() { return ( <div> <BrowserRouter> <Routes> <Route element={<PrivateWrapper key="home-wrapper" />} > <Route path="/" element={<Home />} /> </Route> <Route element={<PrivateWrapper key="about-wrapper" />} > <Route path="/about" element={<About />} /> </Route> </Routes> </BrowserRouter> </div> ) }
方案2:创建独立的路由包装组件
直接创建两个逻辑完全一致但类型不同的包装组件,React 会默认判定为不同组件,自然实现状态隔离:
// 定义独立的包装组件 function HomePrivateWrapper() { return <PrivateWrapper />; } function AboutPrivateWrapper() { return <PrivateWrapper />; } // 在App中使用 function App() { return ( <div> <BrowserRouter> <Routes> <Route element={<HomePrivateWrapper />} > <Route path="/" element={<Home />} /> </Route> <Route element={<AboutPrivateWrapper />} > <Route path="/about" element={<About />} /> </Route> </Routes> </BrowserRouter> </div> ) }
内容的提问来源于stack exchange,提问作者kal_stackO
相关产品推荐
相关产品推荐

