如何在提交风险数据后重新渲染MUI Data Grid表格以同步输入数据
如何在提交风险数据后重新渲染MUI Data Grid表格以同步输入数据
我来帮你解决这个跨组件状态同步的问题!你遇到的核心问题是:Tablepage 只在初始渲染时读取一次localStorage,之后Createrisk提交数据修改localStorage时,它不会自动感知到变化并重新渲染。另外你直接用document.getElementById获取输入值的方式也不符合React的最佳实践,我们可以结合useState和React的数据流来彻底解决这个问题。
方案一:状态提升(最推荐,符合React核心思想)
把风险数据的状态管理放到一个父组件中,让Createrisk和Tablepage都依赖父组件的状态。这样当Createrisk提交数据时,更新父组件的状态,Tablepage会自动接收到新的props并重新渲染。
步骤1:创建父组件(比如App.jsx)
这个组件负责加载初始数据、管理风险状态,并提供更新方法给子组件:
import { useState, useEffect } from 'react'; import Createrisk from './Createrisk'; import Tablepage from './Tablepage'; function App() { // 管理风险数据的全局状态 const [risks, setRisks] = useState([]); // 组件挂载时从localStorage加载初始数据 useEffect(() => { const savedRisks = JSON.parse(localStorage.getItem("allrisks")); if (savedRisks) { // 确保每条风险都有唯一ID(兼容localStorage中已有的数据) const risksWithValidIds = savedRisks.map((risk, index) => ({ ...risk, id: index + 1 })); setRisks(risksWithValidIds); } }, []); // 定义添加新风险的方法,传给Createrisk组件调用 const handleAddNewRisk = (newRisk) => { const updatedRisks = [...risks, newRisk]; // 为所有风险分配连续的唯一ID const risksWithIds = updatedRisks.map((risk, idx) => ({ ...risk, id: idx + 1 })); // 更新父组件状态,触发Tablepage重新渲染 setRisks(risksWithIds); // 同步数据到localStorage持久化 localStorage.setItem("allrisks", JSON.stringify(risksWithIds)); }; return ( <div style={{ padding: '20px' }}> <h2>创建新风险</h2> <Createrisk onAddRisk={handleAddNewRisk} /> <h2>风险列表</h2> <Tablepage risks={risks} /> </div> ); } export default App;
步骤2:修改Createrisk.jsx,用useState管理表单状态
放弃直接操作DOM的方式,用React的状态来控制输入值,这是React处理表单的标准方式:
import { useState } from 'react'; function Createrisk({ onAddRisk }) { // 用useState管理每个输入框的状态 const [riskname, setRiskname] = useState(''); const [riskdesc, setRiskdesc] = useState(''); const [riskimpact, setRiskimpact] = useState(''); const handleSubmission = (e) => { // 阻止按钮默认的表单提交行为(如果包裹在form标签里的话) e.preventDefault(); // 构造新的风险对象 const newRisk = { riskname, riskdesc, riskimpact, test: "test" }; // 调用父组件传来的方法更新全局状态 onAddRisk(newRisk); // 清空表单输入 setRiskname(''); setRiskdesc(''); setRiskimpact(''); }; return ( <div style={{ marginBottom: '30px' }}> <input type="text" placeholder="Risk Name" value={riskname} onChange={(e) => setRiskname(e.target.value)} style={{ marginRight: '10px', padding: '8px' }} /> <input type="text" placeholder="Risk Description" value={riskdesc} onChange={(e) => setRiskdesc(e.target.value)} style={{ marginRight: '10px', padding: '8px' }} /> <input type="text" placeholder="Risk Impact" value={riskimpact} onChange={(e) => setRiskimpact(e.target.value)} style={{ marginRight: '10px', padding: '8px' }} /> <button onClick={handleSubmission} style={{ padding: '8px 16px' }}> Store my data </button> </div> ); } export default Createrisk;
步骤3:修改Tablepage.jsx,接收父组件的props
现在Tablepage不再自己读取localStorage,而是直接使用父组件传递的risks状态,当父组件状态变化时,它会自动重新渲染:
import { DataGrid } from '@mui/x-data-grid'; function Tablepage({ risks }) { const columns = [ { field: "id", headerName: "ID", width: 120 }, { field: "riskname", headerName: "Risk Name", width: 200 }, { field: "riskdesc", headerName: "Risk Description", width: 300 }, { field: "riskimpact", headerName: "Risk Impact", width: 200 }, { field: "test", headerName: "Test", width: 150 }, ]; // 把风险数据转换成DataGrid需要的行格式(也可以直接用risks作为rows,保持代码明确即可) const rows = risks.map(risk => ({ id: risk.id, riskname: risk.riskname, riskdesc: risk.riskdesc, riskimpact: risk.riskimpact, test: risk.test })); return ( <div style={{ height: 400, width: '100%' }}> <DataGrid getRowId={(row) => row.id} columns={columns} rows={rows} /> </div> ); } export default Tablepage;
方案二:监听localStorage变化(适合无需父组件的场景)
如果不想用状态提升,也可以让Tablepage监听localStorage的变化,但要注意:浏览器的storage事件只在其他标签页修改localStorage时触发,同一标签页修改的话需要手动触发刷新:
修改后的Tablepage.jsx:
import { useState, useEffect } from 'react'; import { DataGrid } from '@mui/x-data-grid'; function Tablepage() { const [risks, setRisks] = useState([]); // 加载localStorage数据的工具函数 const loadRisks = () => { const savedRisks = JSON.parse(localStorage.getItem("allrisks")); if (savedRisks) { setRisks(savedRisks); } else { setRisks([]); } }; useEffect(() => { // 初始加载数据 loadRisks(); // 监听自定义事件,当Createrisk提交后触发 const handleRiskAdded = () => { loadRisks(); }; window.addEventListener('riskAdded', handleRiskAdded); // 组件卸载时清理事件监听 return () => { window.removeEventListener('riskAdded', handleRiskAdded); }; }, []); const columns = [ { field: "id", headerName: "ID", width: 120 }, { field: "riskname", headerName: "Risk Name", width: 200 }, { field: "riskdesc", headerName: "Risk Description", width: 300 }, { field: "riskimpact", headerName: "Risk Impact", width: 200 }, { field: "test", headerName: "Test", width: 150 }, ]; return ( <div style={{ height: 400, width: '100%' }}> <DataGrid getRowId={(row) => row.id} columns={columns} rows={risks} /> </div> ); } export default Tablepage;
对应的Createrisk.jsx提交方法需要添加:
function handleSubmission() { // 原来的localStorage保存逻辑不变... localStorage.setItem("allrisks", JSON.stringify(risks)); // 触发自定义事件,通知Tablepage刷新数据 window.dispatchEvent(new CustomEvent('riskAdded')); }
你的原代码存在的核心问题
- 直接操作DOM获取输入值:不符合React状态驱动UI的核心思想,容易导致状态不同步。
- Tablepage未监听数据变化:仅在初始渲染时读取一次localStorage,后续数据更新时不会重新渲染。
- 字段名不匹配:原
Tablepage的columns中用了rname作为字段名,但Createrisk构造的风险对象里是riskname,导致DataGrid无法找到对应数据。 - ID设置逻辑冗余:每次提交都遍历所有风险重置ID,可优化为直接给新风险分配唯一ID。
备注:内容来源于stack exchange,提问作者Aleks3000
相关产品推荐
相关产品推荐

