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
相关产品推荐
相关产品推荐

