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

React中关闭Dialog后实现表格行新增的方案求助

解决方案:提交后无需刷新更新作业列表

要实现提交新项目后自动更新列表,核心是在提交成功后触发列表的重新数据获取。以下是具体步骤和代码修改:


1. 调整App.js:添加刷新触发器

将刷新逻辑的控制权提升到App组件,作为子组件间的通信桥梁:

import { useState } from 'react';
import Navbar from './Navbar';
import ListJobs from './ListJobs';

const App = () => {
  // 用计数器作为刷新触发信号,每次递增都会触发ListJobs重新获取数据
  const [refreshTrigger, setRefreshTrigger] = useState(0);

  // 供子组件调用的刷新函数
  const handleRefreshJobs = () => {
    setRefreshTrigger(prev => prev + 1);
  };

  return (
    <>
      {/* 把刷新函数传递给Navbar */}
      <Navbar onJobAdded={handleRefreshJobs} />
      {/* 把刷新触发器传递给ListJobs */}
      <ListJobs refreshTrigger={refreshTrigger} />
    </>
  );
};

export default App;

2. 修改ListJobs组件:响应刷新触发器并修复状态突变

让ListJobs监听刷新触发器,同时修正直接修改状态的错误:

import { useState, useEffect } from 'react';
import axios from 'axios';
import ActionMenu from './ActionMenu';

const ListJobs = ({ refreshTrigger }) => {
  const [jobData, setJobData] = useState([]);
  const [status, setStatus] = useState([]);

  // 当refreshTrigger变化时,重新获取作业数据
  useEffect(() => {
    const getAllJobs = () => {
      axios.get(baseURLJobs).then((response) => {
        setJobData(response.data);
      });
    };
    getAllJobs();
  }, [refreshTrigger]); // 依赖项添加refreshTrigger

  useEffect(() => {
    const interval = setInterval(() => {
      const getStatus = () => {
        axios.get(baseURLStatus).then((response) => {
          setStatus(response.data);
        });
      };
      getStatus();
    }, 30000);
    return () => clearInterval(interval);
  }, []); // 此处无需依赖status,避免无限循环

  // 合并作业数据和状态,避免直接修改原状态数组
  const mergedJobData = jobData.map(job => {
    const matchingStatus = status.find(s => s.id === job.id);
    return {
      ...job,
      jobStatus: matchingStatus ? matchingStatus.jobStatus : job.jobStatus || 'Unknown'
    };
  });

  return (
    <div>
      <table>
        <thead>
          <tr>
            <th style={{ width: "20%" }}>Job Title</th>
            <th style={{ width: "27%" }}>Job Name</th>
            <th style={{ width: "20%" }}>Date</th>
            <th style={{ width: "21%" }}>Job Status</th>
            <th style={{ width: "12%" }}>Actions</th>
          </tr>
        </thead>
        <tbody>
          {/* 使用合并后的数组渲染 */}
          {mergedJobData.map((item, i) => (
            <tr key={item.id || i}> {/* 优先用id作为key,更稳定 */}
              <td>{item.jobTitle}</td>
              <td>{item.jobName}</td>
              <td>{item.jobCreation}</td>
              <td>{item.jobStatus}</td>
              <td><ActionMenu index={item} /></td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default ListJobs;

3. 更新Navbar组件:传递刷新函数给AddProject

将App中的刷新函数继续传递到AddProject组件:

import { useState } from 'react';
import { Box, AppBar, Toolbar, Typography, Button } from '@mui/material';
import AddProject from './AddProject';

const Navbar = ({ onJobAdded }) => {
  const [openDirectory, setOpenDirectory] = useState(false);

  const handleOpenDirectory = () => setOpenDirectory(true);
  const handleCloseDirectory = () => setOpenDirectory(false);

  return (
    <Box sx={{ flexGrow: 1 }}>
      <AppBar position="static">
        <Toolbar>
          <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
              Reconstruction 2.0
          </Typography>
          <Button onClick={handleOpenDirectory} color="inherit">Add New Project</Button>
        </Toolbar>
      </AppBar>
      {openDirectory && (
        <AddProject
          open={openDirectory}
          onClose={handleCloseDirectory}
          onJobAdded={onJobAdded} {/* 传递刷新函数 */}
        />
      )}
    </Box>
  );
};

export default Navbar;

4. 修改AddProject组件:提交成功后触发刷新

在文件上传成功后,调用刷新函数并关闭弹窗:

import { useState } from 'react';
import { Dialog, TextField } from '@mui/material';
import axios from 'axios';

const AddProject = ({ open, onClose, onJobAdded }) => {
  const [projectName, setProjectName] = useState('');
  const [images, setImages] = useState([]);
  const [yamlFile, setYamlFile] = useState(null);
  const [progress, setProgress] = useState(0);

  const onNameChange = (e) => setProjectName(e.target.value);
  const onImageChange = (e) => setImages(Array.from(e.target.files));
  const onYamlFileChange = (e) => setYamlFile(e.target.files[0]);

  const uploadFiles = async () => {
    try {
      // 构建FormData处理文件上传
      const formData = new FormData();
      formData.append('projectName', projectName);
      images.forEach(img => formData.append('images', img));
      formData.append('yamlFile', yamlFile);

      // 发送POST请求(替换为你的API地址)
      await axios.post('/api/projects', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
        onUploadProgress: (progressEvent) => {
          // 可选:更新上传进度
          const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
          setProgress(percentCompleted);
        }
      });

      // 提交成功后触发列表刷新,再关闭弹窗
      onJobAdded();
      onClose();
      // 重置表单状态
      setProjectName('');
      setImages([]);
      setYamlFile(null);
      setProgress(0);
    } catch (error) {
      console.error('上传失败:', error);
      // 可选:显示错误提示
    }
  };

  return (
    <Dialog open={open} onClose={onClose}>
      <div className='addProjectCard'>
        <h2>Add Project</h2>
        <div className="container">
          <TextField label="Project Name" variant="standard" value={projectName} onChange={onNameChange} />
        </div>
        <div className="container">
          <label className="labelHeading">Images</label>
          <input type="file" multiple accept="image/*" onChange={onImageChange} required />
        </div>
        <div className="container">
          <label className="labelHeading">YAML Files</label>
          <input type="file" accept=".yaml" onChange={onYamlFileChange} required />
        </div>
        <div className="actionContainer">
          <div>Upload Progress is {progress}%</div>
          <button onClick={uploadFiles}>Upload</button>
        </div>
      </div>
    </Dialog>
  );
};

export default AddProject;

关键说明:

  • 状态提升:通过App组件作为中间层,实现子组件间的通信
  • 避免状态突变:使用map和扩展运算符创建新数组,替代直接修改原状态
  • FormData处理文件:文件上传必须使用multipart/form-data格式,通过FormData构建请求体
  • 刷新触发机制:用计数器作为触发信号,确保每次提交后都会重新获取最新数据

内容的提问来源于stack exchange,提问作者Hello World

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:31:09