React MUI组件联动刷新:上传Excel后更新数据表格卡片
React MUI卡片联动刷新方案
问题场景
我用React MUI写了一个包含三个功能卡片的页面:
- 顶部卡片:负责Excel文件上传,上传后数据会提交到后端插入数据库
- 左下卡片:展示已上传的外汇风险数据表格
- 右下卡片:黄金仓位录入功能
现在遇到的问题是:Excel上传完成后,数据表格卡片还显示旧数据,手动刷新页面体验太差,想实现卡片间的联动自动刷新。
原组件代码:
import Typography from '@mui/material/Typography'; import { Grid, Card, CardContent, Box} from '@mui/material'; import MainCard from 'components/MainCard'; import UploadGP from './components/UploadGP'; import UploadExcel from './components/UploadExcel'; import UploadDataTable from './components/UploadDataTable'; export default function FCRUpload() { return ( <MainCard title="Foreign Currency Risk"> <Grid container spacing={2}> {/* Top: Long card spanning full width */} <Grid item xs={12}> <Box> <Card> <CardContent> <Typography variant="h6" gutterBottom> Upload Excel File Here </Typography> <UploadExcel /> </CardContent> </Card> </Box> </Grid> {/* Bottom: Two cards side by side */} <Grid item xs={12} md={6}> <Box mt={2}> <Card> <CardContent> <Typography variant="h6" gutterBottom> Uploaded Foreign Currency Risk Details </Typography> <UploadDataTable /> </CardContent> </Card> </Box> </Grid> <Grid item xs={12} md={6}> <Box mt={2}> <Card> <CardContent> <Typography variant="h6" gutterBottom> Enter Gold Position </Typography> <UploadGP /> </CardContent> </Card> </Box> </Grid> </Grid> </MainCard> ); }
解决方案
方案一:状态提升(最直接的实现方式)
把刷新控制逻辑提到父组件,子组件通过props传递触发刷新的函数,操作完成后通知父组件更新状态,进而触发数据展示组件重新拉取数据。
步骤1:修改父组件,添加刷新状态和触发函数
import { useState } from 'react'; import Typography from '@mui/material/Typography'; import { Grid, Card, CardContent, Box} from '@mui/material'; import MainCard from 'components/MainCard'; import UploadGP from './components/UploadGP'; import UploadExcel from './components/UploadExcel'; import UploadDataTable from './components/UploadDataTable'; export default function FCRUpload() { // 用计数器作为刷新触发标记,每次递增都会触发子组件更新 const [refreshCount, setRefreshCount] = useState(0); // 触发刷新的函数,子组件调用这个函数来通知父组件更新 const triggerRefresh = () => { setRefreshCount(prev => prev + 1); }; return ( <MainCard title="Foreign Currency Risk"> <Grid container spacing={2}> <Grid item xs={12}> <Box> <Card> <CardContent> <Typography variant="h6" gutterBottom> Upload Excel File Here </Typography> {/* 把触发函数传给UploadExcel */} <UploadExcel onUploadSuccess={triggerRefresh} /> </CardContent> </Card> </Box> </Grid> <Grid item xs={12} md={6}> <Box mt={2}> <Card> <CardContent> <Typography variant="h6" gutterBottom> Uploaded Foreign Currency Risk Details </Typography> {/* 把refreshCount传给UploadDataTable,用来监听刷新 */} <UploadDataTable refreshTrigger={refreshCount} /> </CardContent> </Card> </Box> </Grid> <Grid item xs={12} md={6}> <Box mt={2}> <Card> <CardContent> <Typography variant="h6" gutterBottom> Enter Gold Position </Typography> {/* 如果UploadGP操作后也需要刷新表格,同样传递触发函数 */} <UploadGP onSubmitSuccess={triggerRefresh} /> </CardContent> </Card> </Box> </Grid> </Grid> </MainCard> ); }
步骤2:修改UploadExcel组件,上传成功后调用触发函数
假设你的UploadExcel组件里有上传完成的回调:
// UploadExcel.jsx export default function UploadExcel({ onUploadSuccess }) { const handleUpload = async (file) => { try { // 这里是你的上传逻辑,比如调用后端接口 await uploadExcelToBackend(file); // 上传成功后触发刷新 onUploadSuccess(); } catch (error) { console.error('上传失败', error); } }; return ( // 你的上传UI,比如文件选择框、上传按钮等 <div> <input type="file" onChange={(e) => handleUpload(e.target.files[0])} /> </div> ); }
步骤3:修改UploadDataTable组件,监听刷新触发,重新拉取数据
用useEffect监听refreshTrigger的变化,变化时重新请求数据:
// UploadDataTable.jsx import { useState, useEffect } from 'react'; export default function UploadDataTable({ refreshTrigger }) { const [tableData, setTableData] = useState([]); // 拉取数据的函数 const fetchData = async () => { const data = await fetchForeignCurrencyData(); setTableData(data); }; // 组件挂载时和refreshTrigger变化时,重新拉取数据 useEffect(() => { fetchData(); }, [refreshTrigger]); return ( // 你的表格渲染逻辑,比如MUI的DataGrid <div> {/* 渲染tableData */} </div> ); }
方案二:使用React Context(适合复杂组件层级)
如果你的组件层级很深,props传递太麻烦,可以用Context来全局管理刷新状态。
步骤1:创建RefreshContext
// RefreshContext.jsx import { createContext, useContext, useState } from 'react'; const RefreshContext = createContext(); export function RefreshProvider({ children }) { const [refreshCount, setRefreshCount] = useState(0); const triggerRefresh = () => { setRefreshCount(prev => prev + 1); }; return ( <RefreshContext.Provider value={{ refreshCount, triggerRefresh }}> {children} </RefreshContext.Provider> ); } export function useRefresh() { return useContext(RefreshContext); }
步骤2:在父组件外层包裹Provider
// FCRUpload.jsx import { RefreshProvider } from './RefreshContext'; export default function FCRUpload() { return ( <RefreshProvider> <MainCard title="Foreign Currency Risk"> {/* 原有的Grid和卡片代码 */} </MainCard> </RefreshProvider> ); }
步骤3:在子组件中使用Context
- UploadExcel组件:
// UploadExcel.jsx import { useRefresh } from './RefreshContext'; export default function UploadExcel() { const { triggerRefresh } = useRefresh(); const handleUpload = async (file) => { await uploadExcelToBackend(file); triggerRefresh(); }; // 渲染UI }
- UploadDataTable组件:
// UploadDataTable.jsx import { useRefresh } from './RefreshContext'; export default function UploadDataTable() { const { refreshCount } = useRefresh(); const [tableData, setTableData] = useState([]); useEffect(() => { fetchForeignCurrencyData().then(setTableData); }, [refreshCount]); // 渲染表格 }
内容的提问来源于stack exchange,提问作者Vinuka Osura
相关产品推荐
相关产品推荐

