MUI自定义表格结合Formik可编辑字段时排序性能缓慢问题
MUI自定义表格结合Formik可编辑字段时排序性能缓慢问题
我最近开发发票管理表格组件时碰到了性能瓶颈:我写了一个InvoiceTable组件,搭配自定义可编辑发票字段,用Formik统一管理表单状态。在Formik初始化前,我会先计算好initialSortedData;Formik启动后,所有表格数据、排序字段(sortBy)和排序顺序(sortOrder)都存在Formik的values状态里。
目前排序和编辑功能都能正常运行,但排序操作的响应速度特别慢——我的表格行数大概在50-100条,列数则在2到40列之间,这个规模按理说不该有这么明显的卡顿。
下面是我的组件代码,麻烦帮忙看看哪里可能出了问题:
function InvoiceTable() { const classes = useStyles(); const globalClasses = globalStyles(); const [saving, setSaving] = useState(false); const [generatingInvoice, setGeneratingInvoice] = useState(false); const [isAllSelected, setIsAllSelected] = useState(false); const { enqueueSnackbar } = useSnackbar(); const { // State columnsOrder, apiLoading, clientDetails, query, invoiceTableData, noDataFound, page, rowsPerPage, totalRecords, // Functions dispatch, fetchInvoices, LoadingComponent, bulkEditApplied, runSafe, showDialog, confirm, cancel, } = useDashboard(); // State to track the current sorting order and column const [order, setOrder] = useState("asc"); const [orderBy, setOrderBy] = useState(columnsOrder[0]); const previousDataRef = useRef([]); useNavigationBlocker(bulkEditApplied, (proceedFn) => { runSafe(proceedFn); }); /** * Saves invoice data to the database. * @param {{object}} data - The data to be saved to the database. * @returns None * @throws {error} If an error occurs during the saving process. */ const saveInvoiceData = async (data, button = false) => { try { setSaving(true); const query = formatInvoiceDataAndGenerateQuery(data); await Endpoint.Dashboard.updateInvoiceTable({ query }); if (button) { enqueueSnackbar("Data Updated", { variant: "success" }); } if (bulkEditApplied) { dispatch({ type: actionTypes.SET_BULK_EDIT_APPLIED, payload: false }); } setSaving(false); } catch (error) { setSaving(false); console.error("Error:", error); } }; /** * Downloads an Excel file based on the provided data and client details. * @param {{object}} data - The data to be included in the Excel file. * @returns None */ const downloadExcel = async (data) => { try { setGeneratingInvoice(true); await saveInvoiceData(data); // Filter: Keep columnsOrder that are either in `headersToKeep` OR not in `headersToRemove` const filteredHeaders = columnsOrder.filter( (header) => invoiceHeadersToKeep.includes(header) || !invoiceHeadersToRemove.includes(header) ); const payload = { query: query, clientDetails: [clientDetails], invoiceHeaders: filteredHeaders, }; const response = await Endpoint.Dashboard.generateInvoice(payload); if (response) { setGeneratingInvoice(false); window.open(response.data, "_blank"); enqueueSnackbar("Invoice Downloaded!", { variant: "success" }); await fetchInvoices(); } else { setGeneratingInvoice(false); enqueueSnackbar("Something went wrong", { variant: "error" }); } } catch (error) { setGeneratingInvoice(false); console.log(error); } }; /** * Handles the event when a CSV file is chosen by the user. * Reads the file, processes the data, and updates the invoice table data accordingly. * @param {{Event}} event - The event object triggered by choosing a file. * @returns None */ const handleChooseCSV = (event, values, setFieldValue) => { try { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = async (e) => { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: "array" }); const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName]; let jsonData = XLSX.utils.sheet_to_json(sheet, { raw: false }); jsonData = jsonData.map((row) => { // Helper function for safe date conversion const parseDate = (dateValue) => { if (!dateValue) return null; const date = moment(dateValue, ["YYYY-MM-DD", "M/D/YYYY", moment.ISO_8601]); return date.isValid() ? date.format("YYYY-MM-DD") : null; }; // Helper function for safe number parsing const parseNumber = (numValue) => { if (numValue === null || numValue === undefined || numValue === "") return undefined; // Changed to undefined const num = Number(numValue); return isNaN(num) ? undefined : num; // Changed to undefined }; return { work_number: row.work_number || "", // Required field invoice_amount: parseNumber(row.invoice_amount), invoice_notes: row.invoice_notes || null, invoice_number: row.invoice_number || "", invoice_date: parseDate(row.invoice_date), amount_paid: parseNumber(row.amount_paid), check_number: row.check_number || null, check_date: parseDate(row.check_date), check_amount: parseNumber(row.check_amount), check_received_date: parseDate(row.check_received_date) || parseDate(row.payment_date), // Fallback to payment_date }; }); let tempData = [...values.data]; jsonData.forEach((csvRow) => { const index = tempData.findIndex((item) => item.work_number === csvRow.work_number); if (index !== -1) { tempData[index] = { ...tempData[index], ...csvRow }; } }); setFieldValue("data", tempData); }; reader.readAsArrayBuffer(file); } catch (error) { console.error("Error processing CSV:", error); } }; // 注:排序相关的核心逻辑是基于Formik values中的数据进行排序,此处未完全贴出 }
我目前猜测是不是排序时直接操作Formik的values.data导致了不必要的重渲染?或者还有其他优化方向可以参考吗?
内容来源于stack exchange
相关产品推荐
相关产品推荐

