如何在React Router 6中进行状态提升?路由间状态共享咨询
路由间状态共享的解决方案
你的判断是对的,需要把共享状态提升到App组件(而非Layout),原因和具体实现方式如下:
为什么选App而非Layout?
你的Layout组件仅负责渲染Header和Outlet,它本质是布局容器,并不直接包裹ContactList和AddContact这两个路由组件——这两个组件是通过Outlet动态渲染的。而App是这两个组件的最顶层共同父组件,符合React状态提升的核心原则:将共享状态放在需要使用它的所有组件的最上层共同父组件中,这样能确保状态的作用域合理,且所有依赖组件都能访问到。
具体实现方式
方式1:通过props传递(适合简单场景)
你已经在App组件中定义了contacts和setContacts,直接把它们通过props传给两个路由组件即可:
function App() { const [contacts, setContacts] = useState([]) return ( <BrowserRouter> <Routes> <Route element={<Layout />}> {/* 给ContactList传入contacts用于渲染 */} <Route path='/' element={<ContactList contacts={contacts} />} /> {/* 给AddContact传入setContacts用于更新状态,可选传入contacts */} <Route path='/add' element={<AddContact setContacts={setContacts} contacts={contacts} />} /> </Route> </Routes> </BrowserRouter> ); }
在AddContact中调用setContacts更新状态:
import { useNavigate } from 'react-router-dom'; function AddContact({ setContacts, contacts }) { const navigate = useNavigate(); const handleSubmit = (e) => { e.preventDefault(); // 从表单获取新联系人数据,示例用模拟数据 const newContact = { id: Date.now(), name: e.target.name.value, email: e.target.email.value }; // 更新联系人列表 setContacts([...contacts, newContact]); // 添加完成后跳转到列表页 navigate('/'); }; return ( <form onSubmit={handleSubmit}> <input type="text" name="name" placeholder="姓名" required /> <input type="email" name="email" placeholder="邮箱" required /> <button type="submit">添加联系人</button> </form> ); }
在ContactList中直接使用contacts渲染列表:
function ContactList({ contacts }) { return ( <div className="contact-list"> <h2>联系人列表</h2> {contacts.length === 0 ? ( <p>暂无联系人</p> ) : ( contacts.map(contact => ( <div key={contact.id} className="contact-item"> <p>姓名:{contact.name}</p> <p>邮箱:{contact.email}</p> </div> )) )} </div> ); }
方式2:使用React Context(适合复杂场景)
如果后续你的组件层级变深,或者有更多组件需要访问联系人状态,用props传递会变得繁琐,这时可以用Context来管理状态:
首先创建Context和Provider:
import { createContext, useContext, useState } from 'react'; // 创建联系人Context const ContactContext = createContext(); // 创建Provider组件,包裹需要访问状态的组件 export function ContactProvider({ children }) { const [contacts, setContacts] = useState([]); return ( <ContactContext.Provider value={{ contacts, setContacts }}> {children} </ContactContext.Provider> ); } // 自定义Hook,简化Context的使用 export function useContacts() { return useContext(ContactContext); }
然后在App中用ContactProvider包裹路由:
import { ContactProvider } from './ContactContext'; function App() { return ( <ContactProvider> <BrowserRouter> <Routes> <Route element={<Layout />}> <Route path='/' element={<ContactList />} /> <Route path='/add' element={<AddContact />} /> </Route> </Routes> </BrowserRouter> </ContactProvider> ); }
最后在组件中通过自定义Hook获取状态:
// AddContact组件 import { useNavigate } from 'react-router-dom'; import { useContacts } from './ContactContext'; function AddContact() { const { contacts, setContacts } = useContacts(); const navigate = useNavigate(); const handleSubmit = (e) => { e.preventDefault(); const newContact = { id: Date.now(), name: e.target.name.value, email: e.target.email.value }; setContacts([...contacts, newContact]); navigate('/'); }; return ( <form onSubmit={handleSubmit}> {/* 表单内容同上 */} </form> ); } // ContactList组件 import { useContacts } from './ContactContext'; function ContactList() { const { contacts } = useContacts(); return ( <div className="contact-list"> {/* 渲染逻辑同上 */} </div> ); }
内容的提问来源于stack exchange,提问作者Karnveer Grewal
相关产品推荐
相关产品推荐

