You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在提交风险数据后重新渲染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'));
}

你的原代码存在的核心问题

  1. 直接操作DOM获取输入值:不符合React状态驱动UI的核心思想,容易导致状态不同步。
  2. Tablepage未监听数据变化:仅在初始渲染时读取一次localStorage,后续数据更新时不会重新渲染。
  3. 字段名不匹配:原Tablepage的columns中用了rname作为字段名,但Createrisk构造的风险对象里是riskname,导致DataGrid无法找到对应数据。
  4. ID设置逻辑冗余:每次提交都遍历所有风险重置ID,可优化为直接给新风险分配唯一ID。

备注:内容来源于stack exchange,提问作者Aleks3000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:14:31