React路由切换时列表数据无法持久化的问题求助
问题描述
我开发了一个小型React项目,表单提交用户信息后会在同一页面的表格展示,这部分功能正常。但点击Home页面再返回表单页面时,列表就空了。我希望在整个网站浏览过程中列表数据都能保留,求解决方法。
相关组件代码
App.js
import { useState } from "react"; import { Route, Routes } from "react-router-dom"; import Navbar from "./Components/Navbar"; import Home from "./Components/Home"; import PersonList from "./Components/PersonList"; import PersonDetails from "./Components/PersonDetails"; import LoginForm from "./Components/LoginForm"; import { UserContext } from "./Components/UserContext"; import "bootstrap/dist/css/bootstrap.min.css"; import "./App.css"; function App() { const [value, setValue] = useState(null); return ( <div className="App"> <UserContext.Provider value={{value, setValue }}> <Navbar /> <div className="content"> <Routes> <Route path="/" element={<Home />} /> <Route path="/PersonList" element={<PersonList />} /> <Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} /> <Route path="/LoginForm" element={<LoginForm />} /> </Routes> </div> </UserContext.Provider> </div> ); } export default App;
Navbar.js
import { Link } from "react-router-dom"; import { UserContext } from "./UserContext"; import { useContext, useState } from "react"; export default function Navbar() { const {value, setValue} = useContext(UserContext); return ( <nav className="navbar"> <h1>React Assignment</h1> <div className="links"> <Link to="/">Home</Link> <Link to="/PersonList">Person List</Link> { !value && <Link to="/LoginForm">Login</Link> } { value && <Link to="/" onClick={() => {setValue(null);}} >Logout</Link> } {value} </div> </nav> ) }
PersonList.js
import { useState } from "react"; import UserForm from "./UserForm"; import UserList from "./UserList"; const PersonList = () => { // create array using useState to store the contact form data. const [contacts, updateContacts] = useState([]); // update contact state. const addContact = (contact) => { updateContacts([...contacts, contact]); }; return ( <div className="personlist"> <UserForm addContact={addContact} /> <UserList contacts={contacts} /> </div> ); } export default PersonList;
UserForm.js
import { useState } from "react"; import { Form, Button } from "react-bootstrap"; // retrieve addContact function from PersonList.js as props. export default function UserForm({ addContact }) { // useState hook to manage state in functional components. const [contactInfo, setContactInfo] = useState({ firstname: "", lastname: "", age: "", nationality: "", email: "", }); // update input fields. const handleChange = (event) => { setContactInfo({ ...contactInfo, [event.target.name]: event.target.value }); }; // submit data to addContact function. const handleSubmit = (event) => { event.preventDefault(); addContact(contactInfo); // clear input fields after submit setContactInfo({ firstname: "", lastname: "", age: "", nationality: "", email: "", }); }; return ( <div className="form-container w-50"> <Form onSubmit={handleSubmit}> <h3>Contact Form</h3> <Form.Control size="sm" type="text" name="firstname" placeholder="First Name" required value={contactInfo.firstname} onChange={handleChange} /> <Form.Control size="sm" type="text" name="lastname" required placeholder="Last Name" value={contactInfo.lastname} onChange={handleChange} /> <Form.Control size="sm" type="number" name="age" placeholder="Age" value={contactInfo.age} onChange={handleChange} /> <Form.Control size="sm" type="text" name="nationality" placeholder="Nationality" value={contactInfo.nationality} onChange={handleChange} /> <Form.Control size="sm" type="email" name="email" placeholder="Email" required value={contactInfo.email} onChange={handleChange} /> <p></p> <Button variant="primary" size="sm" type="submit"> Submit Contact </Button> <p></p> </Form> </div> ); }
UserList.js
import { Table } from "react-bootstrap"; import uuid from "react-uuid"; import { Link } from "react-router-dom"; // retrieve contacts from PersonList.js as props export default function UserList({ contacts }) { if (contacts.length === 0) { return <h5>The list is empty</h5>; } else { return ( <Table className="w-100" bordered hover size="sm"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Age</th> <th>Nationality</th> <th>Email</th> </tr> </thead> <tbody className="tablelinks"> {/* use .map to loop */} {contacts.map((contact) => ( <tr key={uuid()}> <td> <Link to={`/Components/PersonDetails/${contact.firstname+contact.lastname}`}> {contact.firstname} </Link> </td> <td>{contact.lastname}</td> <td>{contact.age}</td> <td>{contact.nationality}</td> <td>{contact.email}</td> </tr> ))} </tbody> </Table> ); } }
解决方案
问题根源
PersonList组件内部的contacts状态会随组件卸载而丢失——当你切换到Home页面时,PersonList被卸载,状态清空;返回时组件重新挂载,contacts回到初始空数组。
修复步骤
利用已有的UserContext把联系人状态提升到App组件(全局上下文层级),确保状态不随组件卸载丢失:
- 修改
App.js,添加联系人状态到上下文:
import { useState } from "react"; import { Route, Routes } from "react-router-dom"; import Navbar from "./Components/Navbar"; import Home from "./Components/Home"; import PersonList from "./Components/PersonList"; import PersonDetails from "./Components/PersonDetails"; import LoginForm from "./Components/LoginForm"; import { UserContext } from "./Components/UserContext"; import "bootstrap/dist/css/bootstrap.min.css"; import "./App.css"; function App() { const [value, setValue] = useState(null); // 添加全局联系人状态 const [contacts, setContacts] = useState([]); return ( <div className="App"> <UserContext.Provider value={{value, setValue, contacts, setContacts }}> <Navbar /> <div className="content"> <Routes> <Route path="/" element={<Home />} /> <Route path="/PersonList" element={<PersonList />} /> <Route path="/Components/PersonDetails/:id/*" element={<PersonDetails />} /> <Route path="/LoginForm" element={<LoginForm />} /> </Routes> </div> </UserContext.Provider> </div> ); } export default App;
- 修改
PersonList组件,从上下文获取状态,移除内部状态:
import { useContext } from "react"; import UserForm from "./UserForm"; import UserList from "./UserList"; import { UserContext } from "./UserContext"; const PersonList = () => { const { contacts, setContacts } = useContext(UserContext); const addContact = (contact) => { setContacts([...contacts, contact]); }; return ( <div className="personlist"> <UserForm addContact={addContact} /> <UserList contacts={contacts} /> </div> ); } export default PersonList;
- 额外优化:避免
UserList中每次渲染生成新key
修改addContact函数,给每个联系人添加唯一id:
const addContact = (contact) => { setContacts([...contacts, { ...contact, id: uuid() }]); };
然后在UserList中使用contact.id作为key:
<tr key={contact.id}>
完成以上修改后,联系人数据会存储在全局上下文中,路由切换时不会丢失,整个浏览过程中数据都会保留。
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

