
本文介绍使用 react router 与 context api 实现父子组件及跨路由页面间的数据传递,解决点击编辑按钮后 `row` 数据丢失的问题,确保 `editrecord` 页面能可靠获取原始记录。
在 React 应用中,当用户点击表格中的“编辑”按钮跳转到 /edit 页面时,若仅通过局部 useState 设置数据并立即导航(如 href 跳转),该状态将因组件卸载而丢失——这正是你遇到 record props 消失的根本原因。关键在于:状态需提升至路由级共享作用域,并配合声明式导航触发数据持久化。
✅ 正确做法:React Router + Context 管理跨页数据
1. 配置路由(App.js)
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import ParentComponent from './ParentComponent';
import EditRecord from './EditRecord';
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={ParentComponent} />
<Route path="/edit" component={EditRecord} />
</Switch>
</Router>
);
}
export default App;2. 创建全局数据上下文(RecordContext.js)
import React, { createContext, useState, useContext } from 'react';
const RecordContext = createContext();
export const RecordProvider = ({ children }) => {
const [record, setRecord] = useState({});
return (
<RecordContext.Provider value={{ record, setRecord }}>
{children}
</RecordContext.Provider>
);
};
export const useRecord = () => {
const context = useContext(RecordContext);
if (!context) throw new Error('useRecord must be used within RecordProvider');
return context;
};3. 包裹根组件(index.js 或 Root.js)
import React from 'react';
import ReactDOM from 'react-dom/client';
import { RecordProvider } from './RecordContext';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<RecordProvider>
<App />
</RecordProvider>
);4. 父组件:点击时存数据 + 编程式导航(ParentComponent.js)
⚠️ 重要修正:移除 <a href> 和内联 setRecord,改用 useHistory(v5)或 useNavigate(v6)
import React from 'react';
import { useNavigate } from 'react-router-dom'; // v6 写法(推荐)
import { useRecord } from './RecordContext';
const ParentComponent = ({ data }) => {
const navigate = useNavigate();
const { setRecord } = useRecord();
const handleEdit = (row) => {
setRecord(row); // ✅ 存入全局上下文
navigate('/edit'); // ✅ 编程式导航,不触发页面刷新
};
return (
<TableBody>
{data.map((row, index) => (
<TableRow key={index}>
<TableCell>
<Button onClick={() => handleEdit(row)}>
<EditNoteOutlined color="primary" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
);
};
export default ParentComponent;5. 子页面:从上下文读取数据(EditRecord.js)
import React from 'react';
import { useRecord } from './RecordContext';
const EditRecord = () => {
const { record } = useRecord();
// ✅ 此处 record 始终为最新选中的行数据
if (!Object.keys(record).length) {
return <div>未选择要编辑的记录,请返回列表页</div>;
}
return (
<div>
<h2>编辑记录</h2>
<pre>{JSON.stringify(record, null, 2)}</pre>
{/* 此处可接入表单、API 提交等逻辑 */}
</div>
);
};
export default EditRecord;⚠️ 注意事项与替代方案
- 不要用 href 跳转 + useState:<a href> 是硬跳转,会销毁当前组件实例,本地状态必然丢失。
- 避免 URL 参数传复杂对象:?id=123 适合简单 ID,但 row 若含嵌套结构或二进制数据,应走状态管理而非序列化到 URL。
-
进阶场景建议:
- 数据量大或需服务端同步 → 使用 Redux Toolkit 或 Zustand;
- 多级嵌套路由 → 结合 useParams + 后端查询,而非前端传整个对象;
- 需持久化(刷新不丢)→ 在 setRecord 时同步写入 sessionStorage。
通过 Context + Router 的组合,你构建了一个轻量、可维护、符合 React 思想的跨页数据流,既规避了 prop-drilling,又保证了状态生命周期与路由一致。


















