☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜
{"type":"doc","content":[{"type":"heading","attrs":{"id":"a33e361c-c561-4d9a-8729-dc4b169b1bf8","textalign":"inherit","indent":0,"level":1,"ishoverdraghandle":false},"content":[{"type":"text","text":"引言 "}]},{"type":"paragraph","attrs":{"id":"edecbe31-b7fd-450b-8453-2c7ed6a2f938","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","text":"从采购订单行项、发货明细到库存批次追踪,一个高性能、可编辑且体验流畅的表格,是提升运营人员效率、确保数据准确性的关键战场。传统的"},{"type":"text","marks":[{"type":"code"}],"text":"u003ctableu003e"},{"type":"text","text":"标签或简单ui库表格组件,在面对供应链场景下的"},{"type":"text","marks":[{"type":"bold"}],"text":"大数据量渲染、复杂单元格编辑、实时数据更新"},{"type":"text","text":"与"},{"type":"text","marks":[{"type":"bold"}],"text":"深层次联动校验"},{"type":"text","text":"时,往往捉襟见肘,导致页面卡顿、交互笨拙。"}]},{"type":"paragraph","attrs":{"id":"138f9d16-60df-4371-9336-84ea1b8e4745","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","text":"本文将深入探讨如何集成业界领先的 "},{"type":"text","marks":[{"type":"bold"}],"text":"tanstack table (v8)"},{"type":"text","text":" 库,结合现代化的react状态管理,为电商供应链系统打造一个坚实、灵活且极致性能的数据表格解决方案,让它真正成为业务的得力助手,而非性能瓶颈。"}]},{"type":"heading","attrs":{"id":"afd66d95-c6ec-4db3-bc13-67a1f5f1c5bc","textalign":"inherit","indent":0,"level":1,"ishoverdraghandle":false},"content":[{"type":"text","text":"一、为什么选择 tanstack table?供应链表格的严苛挑战 "}]},{"type":"paragraph","attrs":{"id":"b6889dbf-edfa-450a-a644-70dc480b9bf1","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","text":"在深入代码之前,我们首先需要明确供应链明细表格的核心挑战与选型依据。"}]},{"type":"bulletlist","attrs":{"id":"8924c0e4-a229-47c2-be57-9163aa003c52","ishoverdraghandle":false},"content":[{"type":"listitem","attrs":{"id":"d4ff5235-4018-4fb1-82b1-806d40bdd71a"},"content":[{"type":"paragraph","attrs":{"id":"da3b2061-974d-49ae-bf8e-7347d01ac5f3","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"海量数据渲染性能"},{"type":"text","text":":单次可能需要展示数千甚至上万条sku的库存明细或历史订单记录。"}]}]},{"type":"listitem","attrs":{"id":"8c4e8b76-b6a3-40ba-a5e2-f05096891b39"},"content":[{"type":"paragraph","attrs":{"id":"d7890ca0-11df-44b5-ad18-942221e67f70","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"复杂的单元格编辑"},{"type":"text","text":":需要支持快速的内联编辑、下拉选择、日期选择、数字格式化与校验。"}]}]},{"type":"listitem","attrs":{"id":"5323ae25-3038-4ebd-a65f-eeaea7a34284"},"content":[{"type":"paragraph","attrs":{"id":"ca14729c-f2b1-4897-b153-ef7a06350d21","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"动态列与列操作"},{"type":"text","text":":不同仓库、不同业务角色(如采购、质检、财务)需要看到和操作的列可能不同。"}]}]},{"type":"listitem","attrs":{"id":"1b283416-9cba-4596-b8ae-18cda2d86217"},"content":[{"type":"paragraph","attrs":{"id":"a212473a-0eb6-4630-a99c-033f7b9929b3","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"强大的排序、筛选与分组"},{"type":"text","text":":用户需要从多维度快速定位目标数据,例如按库存状态筛选、按供应商分组。"}]}]},{"type":"listitem","attrs":{"id":"b60f808d-09f6-4378-841b-903c43e35286"},"content":[{"type":"paragraph","attrs":{"id":"94909269-6b6c-40b5-912e-8c57800449a2","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"行选与批量操作"},{"type":"text","text":":批量修改库存状态、批量发起质检或打印发货单是常见操作。"}]}]},{"type":"listitem","attrs":{"id":"7d72fc1d-8c99-4284-bcfb-7e1ae1ab7c47"},"content":[{"type":"paragraph","attrs":{"id":"05001a25-bb56-4cec-9a55-29f12b69297c","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"与全局数据流联动"},{"type":"text","text":":表格数据的修改需要无缝同步至状态管理层(如context/redux)或触发后端api调用。"}]}]}]},{"type":"paragraph","attrs":{"id":"98fb825d-c063-4b87-b237-6a5d026510b9","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","text":"tanstack table 完美应对了以上挑战:"}]},{"type":"bulletlist","attrs":{"id":"d21b4c1e-2bb3-4edb-9d89-3aaa142db07a","ishoverdraghandle":false},"content":[{"type":"listitem","attrs":{"id":"64710621-f11b-4976-8205-3a1d248d9d61"},"content":[{"type":"paragraph","attrs":{"id":"a00fdb3c-6364-4f49-9fe3-238f151d410c","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"无头(headless)设计"},{"type":"text","text":":它不负责渲染任何ui元素,只提供全部的状态、逻辑和api。我们将100%掌控表格的样式、结构和交互,轻松融入现有设计系统。"}]}]},{"type":"listitem","attrs":{"id":"07122d7f-a55a-4835-9f8e-6212fccdc0ad"},"content":[{"type":"paragraph","attrs":{"id":"1569a672-e662-4afa-bacb-8870f4060599","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"惊人的性能"},{"type":"text","text":":基于hooks的架构,配合虚拟化渲染(需结合"},{"type":"text","marks":[{"type":"code"}],"text":"@tanstack/react-virtual"},{"type":"text","text":"),即使处理10w+行数据也能保持流畅滚动。"}]}]},{"type":"listitem","attrs":{"id":"08d79586-6015-498a-a66e-276c00496f0b"},"content":[{"type":"paragraph","attrs":{"id":"025d2508-fe27-4d2a-a8e3-11c83442c011","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"极强的灵活性"},{"type":"text","text":":编辑、筛选、排序、分组、行选、列可见性控制等功能均以特性(feature)形式提供,可按需组合和深度定制。"}]}]},{"type":"listitem","attrs":{"id":"02b86cd7-bcc4-4490-8205-c945b1aa27a8"},"content":[{"type":"paragraph","attrs":{"id":"02611741-325d-42f4-9200-570f30b316cc","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"框架无关性核心"},{"type":"text","text":":其核心逻辑("},{"type":"text","marks":[{"type":"code"}],"text":"@tanstack/table-core"},{"type":"text","text":")与ui框架解耦,保证了api的稳定性和react版本的长期兼容性。"}]}]}]},{"type":"heading","attrs":{"id":"bc8b0d89-2dca-44d3-aae7-6d296958b369","textalign":"inherit","indent":0,"level":1,"ishoverdraghandle":false},"content":[{"type":"text","text":"二、项目环境搭建与基础表格渲染 "}]},{"type":"paragraph","attrs":{"id":"12ad2ffb-a8d6-4692-ad67-197628bbae84","textalign":"inherit","indent":0,"color":null,"background":null,"ishoverdraghandle":false},"content":[{"type":"text","text":"首先,我们初始化一个react项目并安装必要的依赖。本文基于纯javascript环境。"}]},{"type":"codeblock","attrs":{"id":"8b6e674e-3c3f-4d11-b2a0-2cb5ea3cc4da","language":"javascript","theme":"atom-one-dark","runtimes":0,"ishoverdraghandle":false,"key":"","languagebyai":"javascript"},"content":[{"type":"text","text":"# 创建react应用 (使用vite作为构建工具,更轻量快速)
pm create vite@latest supply-chain-table -- --template reactcd supply-chain-table\# 安装核心依赖
pm install @tanstack/react-table# 安装图标库(用于操作按钮)和日期处理库
pm install lucide-react date-fns# 安装用于数据模拟和管理的工具
pm install @tanstack/react-query axios"}]},{"type":"paragraph","attrs":{"id":"1fbed2b3-572f-43d4-a10a-be1c702a7b7a","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"接下来,我们创建一个模拟数据服务和基础表格组件。"}]},{"type":"paragraph","attrs":{"id":"a9fa0917-58ce-4f29-bd94-f5db143c287f","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"1. 模拟数据与API服务 ("},{"type":"text","marks":[{"type":"code"}],"text":"src/services/inventoryService.js"},{"type":"text","marks":[{"type":"bold"}],"text":")"}]},{"type":"codeBlock","attrs":{"id":"179d3bac-0ded-4ef9-aafa-6177f722b256","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"import { generate } from '@tanstack/react-table';\// 模拟生成供应链库存明细数据const generateInventoryData = (count) =u003e { const skus = ['SKU-1001', 'SKU-1002', 'SKU-2001', 'SKU-3005']; const statuses = ['在库', '待检', '预留', '冻结', '已出库']; const warehouses = ['华东中心仓', '华南保税仓', '北京仓']; return Array.from({ length: count }, (_, index) =u003e ({ id: index + 1, sku: skus[Math.floor(Math.random() * skus.length)] + `-B${String(index).padStart(5, '0')}`, productName: `商品 ${['高级', '标准', '试用装'][index % 3]} ${index + 1}`, batchNumber: `BATCH-2024-${String(index).padStart(4, '0')}`, warehouse: warehouses[index % warehouses.length], currentQuantity: Math.floor(Math.random() * 1000) + 100, allocatedQuantity: Math.floor(Math.random() * 100), availableQuantity: 0, // 将通过计算得出 status: statuses[index % statuses.length], lastUpdated: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString(), })).map(item =u003e ({ ...item, availableQuantity: item.currentQuantity - item.allocatedQuantity, // 计算可用库存 }));};\// 模拟API函数export const fetchInventoryData = async ({ pageIndex, pageSize }) =u003e { // 模拟网络延迟 await new Promise(resolve =u003e setTimeout(resolve, 300)); const allData = generateInventoryData(1000); const start = pageIndex * pageSize; const end = start + pageSize; const pageData = allData.slice(start, end); return { data: pageData, total: allData.length, // 总数用于分页 };};"}]},{"type":"paragraph","attrs":{"id":"fc5e684c-acca-45eb-808b-07c6dc4de341","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"代码解析"},{"type":"text","text":":"}]},{"type":"bulletList","attrs":{"id":"f9357f8e-76f8-4ffb-a46c-33356ff591f3","isHoverDragHandle":false},"content":[{"type":"listItem","attrs":{"id":"983b0410-5e1e-46be-8250-37c407cbdea4"},"content":[{"type":"paragraph","attrs":{"id":"e2fdd3f8-a645-4cce-a838-1677d0959c8b","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"定义了"},{"type":"text","marks":[{"type":"code"}],"text":"generateInventoryData"},{"type":"text","text":"函数,生成包含"},{"type":"text","marks":[{"type":"code"}],"text":"id"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"code"}],"text":"sku"},{"type":"text","text":"、批次、仓库、库存数量、状态等典型字段的模拟数据。"}]}]},{"type":"listItem","attrs":{"id":"490bd2d5-aa5a-4c08-9a05-1a411150f0e2"},"content":[{"type":"paragraph","attrs":{"id":"d4edede9-e3a1-4a1a-b5b8-7503fd36d7fd","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"code"}],"text":"availableQuantity"},{"type":"text","text":"(可用库存)通过计算得出,模拟了业务逻辑。"}]}]},{"type":"listItem","attrs":{"id":"c3ab0494-de7f-423d-b656-5410fb5a3f74"},"content":[{"type":"paragraph","attrs":{"id":"4107253b-0881-4c2a-a20d-c65b2944836b","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"code"}],"text":"fetchInventoryData"},{"type":"text","text":"函数模拟了一个分页查询API,接收分页参数,返回一页数据及数据总量,并添加了300ms延迟以模拟真实网络请求。"}]}]}]},{"type":"paragraph","attrs":{"id":"add46e46-371c-4c52-8e79-4408b1266020","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"2. 基础表格组件 ("},{"type":"text","marks":[{"type":"code"}],"text":"src/components/InventoryTable.jsx"},{"type":"text","marks":[{"type":"bold"}],"text":")"}]},{"type":"codeBlock","attrs":{"id":"37795e3a-ce9b-4c0d-abbf-679eff7ab209","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"import React, { useMemo } from 'react';import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender } from '@tanstack/react-table';import { useQuery } from '@tanstack/react-query';import { fetchInventoryData } from '../services/inventoryService';import { ArrowUpDown, MoreVertical } from 'lucide-react';import '../styles/table.css'; // 基础样式\const InventoryTable = () =u003e { // 使用React Query管理服务器状态、缓存和分页 const { data: apiData, isLoading, isError } = useQuery({ queryKey: ['inventory', { pageIndex: 0, pageSize: 20 }], // 初始第一页 queryFn: () =u003e fetchInventoryData({ pageIndex: 0, pageSize: 20 }), });\ const data = useMemo(() =u003e apiData?.data || [], [apiData]); const total = apiData?.total || 0;\ // 1. 定义列配置 const columns = useMemo( () =u003e [ { accessorKey: 'sku', header: 'SKU编码', cell: ({ getValue }) =u003e u003cstrongu003e{getValue()}u003c/strongu003e, // 自定义单元格渲染 size: 150, // 控制列宽 }, { accessorKey: 'productName', header: '商品名称', size: 200, }, { accessorKey: 'batchNumber', header: '生产批次', size: 150, }, { accessorKey: 'warehouse', header: '所在仓库', size: 120, }, { accessorKey: 'currentQuantity', header: '当前库存', // 添加排序功能 enableSorting: true, }, { accessorKey: 'availableQuantity', header: '可用库存', enableSorting: true, }, { accessorKey: 'status', header: '库存状态', cell: ({ getValue }) =u003e { const status = getValue(); const statusConfig = { '在库': { color: 'green', bg: '#f0fdf4' }, '待检': { color: 'orange', bg: '#fff7ed' }, '预留': { color: 'blue', bg: '#eff6ff' }, '冻结': { color: 'red', bg: '#fef2f2' }, '已出库': { color: 'gray', bg: '#f3f4f6' }, }; const config = statusConfig[status] || {}; return ( u003cspan className=\"status-badge\" style={{ color: config.color, backgroundColor: config.bg }}u003e {status} u003c/spanu003e ); }, }, { id: 'actions', header: '操作', cell: () =u003e ( u003cbutton className=\"icon-button\"u003e u003cMoreVertical size={16} /u003e u003c/buttonu003e ), size: 80, }, ], [] );\ // 2. 使用useReactTable Hook创建表格实例 const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), // 必需:获取核心行模型 getSortedRowModel: getSortedRowModel(), // 启用排序 // 可以在此处定义初始状态,如排序规则 initialState: { sorting: [{ id: 'availableQuantity', desc: true }], // 默认按可用库存降序 }, });\ if (isLoading) return u003cdivu003e加载库存数据中...u003c/divu003e; if (isError) return u003cdivu003e数据加载失败,请重试。u003c/divu003e;\ // 3. 渲染表格UI return ( u003cdiv className=\"table-container\"u003e u003cdiv className=\"table-header\"u003e u003ch2u003e供应链库存明细u003c/h2u003e u003cdivu003e总计: {total} 条记录u003c/divu003e u003c/divu003e u003ctableu003e u003ctheadu003e {table.getHeaderGroups().map(headerGroup =u003e ( u003ctr key={headerGroup.id}u003e {headerGroup.headers.map(header =u003e { const column = header.column; return ( u003cth key={header.id} style={{ width: header.getSize() }}u003e u003cdiv onClick={column.getToggleSortingHandler()} className=\"sortable-header\"u003e {flexRender(column.columnDef.header, header.getContext())} {column.getCanSort() u0026u0026 u003cArrowUpDown size={14} /u003e} u003c/divu003e u003c/thu003e ); })} u003c/tru003e ))} u003c/theadu003e u003ctbodyu003e {table.getRowModel().rows.map(row =u003e ( u003ctr key={row.id}u003e {row.getVisibleCells().map(cell =u003e ( u003ctd key={cell.id}u003e {flexRender(cell.column.columnDef.cell, cell.getContext())} u003c/tdu003e ))} u003c/tru003e ))} u003c/tbodyu003e u003c/tableu003e u003c/divu003e );};\export default InventoryTable;"}]},{"type":"paragraph","attrs":{"id":"aa37a31a-eef9-44df-8db2-9422fdb40bcd","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"代码解析"},{"type":"text","text":":"}]},{"type":"bulletList","attrs":{"id":"8a3d1eed-e35f-4f8b-a556-84ecc0fab078","isHoverDragHandle":false},"content":[{"type":"listItem","attrs":{"id":"2f2b1ff6-f121-4504-99aa-8ddc8ad45c62"},"content":[{"type":"paragraph","attrs":{"id":"099412ba-8584-41e4-8d8e-7fb96146fe7c","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"列定义"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"columns"},{"type":"text","text":"数组是表格的核心配置。"},{"type":"text","marks":[{"type":"code"}],"text":"accessorKey"},{"type":"text","text":"对应数据对象的键。"},{"type":"text","marks":[{"type":"code"}],"text":"header"},{"type":"text","text":"定义列标题。"},{"type":"text","marks":[{"type":"code"}],"text":"cell"},{"type":"text","text":"函数允许完全自定义单元格渲染内容,我们用它来渲染加粗的SKU和带颜色的状态标签。"},{"type":"text","marks":[{"type":"code"}],"text":"enableSorting"},{"type":"text","text":"启用该列排序。"}]}]},{"type":"listItem","attrs":{"id":"555df0f9-8aed-4cfb-86c0-37ef77cba6d7"},"content":[{"type":"paragraph","attrs":{"id":"2af3e5e9-37ba-4bbe-8512-8c5a098b57ed","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"创建Table实例"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"useReactTable"},{"type":"text","text":"Hook接收"},{"type":"text","marks":[{"type":"code"}],"text":"data"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"code"}],"text":"columns"},{"type":"text","text":"和一系列模型插件。"},{"type":"text","marks":[{"type":"code"}],"text":"getCoreRowModel"},{"type":"text","text":"是必需的,"},{"type":"text","marks":[{"type":"code"}],"text":"getSortedRowModel"},{"type":"text","text":"提供了排序状态和逻辑。"},{"type":"text","marks":[{"type":"code"}],"text":"initialState"},{"type":"text","text":"设置了表格的初始排序状态。"}]}]},{"type":"listItem","attrs":{"id":"af7ee775-9748-49d4-a1b2-653b55648894"},"content":[{"type":"paragraph","attrs":{"id":"0c397951-c396-40f0-b9ae-c4f9d79a0ab0","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"渲染"},{"type":"text","text":":通过"},{"type":"text","marks":[{"type":"code"}],"text":"table.getHeaderGroups()"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"code"}],"text":"table.getRowModel().rows"},{"type":"text","text":"来获取表头和行数据进行渲染。"},{"type":"text","marks":[{"type":"code"}],"text":"flexRender"},{"type":"text","text":"是TanStack Table提供的渲染工具,用于解析和渲染列定义中"},{"type":"text","marks":[{"type":"code"}],"text":"header"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"code"}],"text":"cell"},{"type":"text","text":"的内容。"},{"type":"text","marks":[{"type":"code"}],"text":"column.getToggleSortingHandler()"},{"type":"text","text":"为可排序列生成点击排序的事件处理器。"}]}]}]},{"type":"image","attrs":{"id":"f639ba8c-69b2-4066-a3f5-367fbc2966f5","src":"https://developer.qcloudimg.com/http-save/audit-10133498/7737b0501ca4bd116f43680ad47b67b4.png","extension":"png","align":"center","alt":"","showAlt":false,"href":"","boxShadow":"","width":1012,"aspectRatio":"0.869811","status":"success","showText":true,"isPercentage":false,"percentage":0,"isHoverDragHandle":false}},{"type":"heading","attrs":{"id":"2d6dd8e9-0fa6-4234-af4f-736b8d1c111b","textAlign":"inherit","indent":0,"level":1,"isHoverDragHandle":false},"content":[{"type":"text","text":"三、实现可编辑单元格与行内编辑 "}]},{"type":"paragraph","attrs":{"id":"b42af02c-8528-4397-9263-0dccdc3d61f1","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"供应链表格的核心交互之一是快速修改。我们实现一个内联编辑功能:点击单元格进入编辑模式,修改后保存或取消。"}]},{"type":"codeBlock","attrs":{"id":"abc76ea3-d923-4b0e-a5ba-dec9aa59e167","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"// 在InventoryTable组件中添加状态和编辑逻辑import React, { useState, useMemo } from 'react';// ... 其他导入保持不变import { Edit2, Check, X } from 'lucide-react';\const EditableCell = ({ getValue, row, column, table }) =u003e { const initialValue = getValue(); const [isEditing, setIsEditing] = useState(false); const [value, setValue] = useState(initialValue);\ const onSave = () =u003e { // 此处应触发全局状态更新或API调用 console.log(`保存行 ${row.id}, 列 ${column.id} 的值为:`, value); // 模拟更新表格数据(实际中应更新状态管理中的数据) table.options.meta?.updateData(row.index, column.id, value); setIsEditing(false); };\ const onCancel = () =u003e { setValue(initialValue); setIsEditing(false); };\ if (isEditing) { return ( u003cdiv className=\"editing-cell\"u003e u003cinput value={value} onChange={(e) =u003e setValue(e.target.value)} autoFocus /u003e u003cdiv className=\"edit-actions\"u003e u003cbutton onClick={onSave}u003eu003cCheck size={14}/u003eu003c/buttonu003e u003cbutton onClick={onCancel}u003eu003cX size={14}/u003eu003c/buttonu003e u003c/divu003e u003c/divu003e ); }\ return ( u003cdiv className=\"display-cell\" onClick={() =u003e setIsEditing(true)}u003e {getValue()} u003cEdit2 size={12} className=\"edit-icon\" /u003e u003c/divu003e );};\// 然后,在columns配置中,将需要编辑的列的`cell`属性替换const columns = useMemo( () =u003e [ // ... 其他列定义 { accessorKey: 'currentQuantity', header: '当前库存', enableSorting: true, cell: (props) =u003e u003cEditableCell {...props} /u003e, // 使用可编辑单元格组件 }, { accessorKey: 'allocatedQuantity', header: '已分配', cell: (props) =u003e u003cEditableCell {...props} /u003e, }, // ... 其他列 ], []);\// 在调用useReactTable时,需要传入meta对象以供子组件调用更新函数const [tableData, setTableData] = useState(data); // 使用本地状态管理表格数据\const table = useReactTable({ data: tableData, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), meta: { // 定义meta对象,用于跨组件通信 updateData: (rowIndex, columnId, value) =u003e { setTableData(old =u003e old.map((row, index) =u003e { if (index === rowIndex) { return { ...old[rowIndex], [columnId]: value }; } return row; })); }, }, initialState: { sorting: [{ id: 'availableQuantity', desc: true }], },});"}]},{"type":"paragraph","attrs":{"id":"7432301b-08b8-4891-8537-46ead9170e39","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"代码解析"},{"type":"text","text":":"}]},{"type":"bulletList","attrs":{"id":"4df54527-65db-4785-b315-bb21cfee74df","isHoverDragHandle":false},"content":[{"type":"listItem","attrs":{"id":"714f8e66-84d8-4d0f-9bc1-b30281dffb34"},"content":[{"type":"paragraph","attrs":{"id":"203b3479-77d4-4e61-ba32-5c0a11d432ec","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"code"}],"text":"EditableCell"},{"type":"text","marks":[{"type":"bold"}],"text":"组件"},{"type":"text","text":":接收TanStack Table传递的"},{"type":"text","marks":[{"type":"code"}],"text":"cell"},{"type":"text","text":"属性。它管理编辑状态("},{"type":"text","marks":[{"type":"code"}],"text":"isEditing"},{"type":"text","text":")和输入值("},{"type":"text","marks":[{"type":"code"}],"text":"value"},{"type":"text","text":")。"}]}]},{"type":"listItem","attrs":{"id":"61c7a1e9-de03-4f02-a761-f18838da73b0"},"content":[{"type":"paragraph","attrs":{"id":"b769c295-e6c1-4b6b-aa0d-1d238648749f","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"交互流程"},{"type":"text","text":":默认显示值和一个编辑图标。点击后切换到编辑模式,显示输入框和保存/取消按钮。保存时,通过"},{"type":"text","marks":[{"type":"code"}],"text":"table.options.meta.updateData"},{"type":"text","text":"回调函数,将修改传回表格组件,更新本地数据状态。取消则恢复原值。"}]}]},{"type":"listItem","attrs":{"id":"6ab4e5c2-3b0e-44a8-9042-1d21c221a881"},"content":[{"type":"paragraph","attrs":{"id":"24333176-3f59-4aff-845b-ad214b680542","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"code"}],"text":"meta"},{"type":"text","marks":[{"type":"bold"}],"text":"对象"},{"type":"text","text":":这是TanStack Table提供的一种跨组件传递数据和函数的机制。我们在"},{"type":"text","marks":[{"type":"code"}],"text":"table"},{"type":"text","text":"配置中定义了一个"},{"type":"text","marks":[{"type":"code"}],"text":"updateData"},{"type":"text","text":"函数,用于更新父组件中的"},{"type":"text","marks":[{"type":"code"}],"text":"tableData"},{"type":"text","text":"状态。"},{"type":"text","marks":[{"type":"code"}],"text":"EditableCell"},{"type":"text","text":"通过"},{"type":"text","marks":[{"type":"code"}],"text":"table.options.meta"},{"type":"text","text":"访问到这个函数。"}]}]}]},{"type":"image","attrs":{"id":"d7aede4c-5bc0-4889-a6f6-5bf026b613f2","src":"https://developer.qcloudimg.com/http-save/audit-10133498/6dde4da04eeeca392c65dcd5b4131f36.png","extension":"png","align":"center","alt":"","showAlt":false,"href":"","boxShadow":"","width":1012,"aspectRatio":"0.530939","status":"success","showText":true,"isPercentage":false,"percentage":0,"isHoverDragHandle":false}},{"type":"heading","attrs":{"id":"4dd233e5-f4c8-47ab-b21f-71c3e33f5d72","textAlign":"inherit","indent":0,"level":1,"isHoverDragHandle":false},"content":[{"type":"text","text":"四、集成行选择与批量操作 "}]},{"type":"paragraph","attrs":{"id":"81447c14-1e88-4179-a99e-92c24b52a6ee","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"批量操作是供应链管理的高频需求。TanStack Table提供了行选择功能。"}]},{"type":"codeBlock","attrs":{"id":"ae9f280e-1bfe-423a-92e3-a59118224e36","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"// 1. 引入行选择插件import { getCoreRowModel, getSortedRowModel, getPaginationRowModel, getFilteredRowModel, getFacetedRowModel, getFacetedUniqueValues, getFacetedMinMaxValues, getPaginationRowModel, getSortedRowModel, getFilteredRowModel, getFacetedRowModel, getFacetedUniqueValues, getFacetedMinMaxValues, getGroupedRowModel, getExpandedRowModel, getSelectedRowModel, // 新增} from '@tanstack/react-table';\// 2. 在columns中添加选择列const columns = useMemo( () =u003e [ { id: 'select', header: ({ table }) =u003e ( u003cinput type=\"checkbox\" checked={table.getIsAllRowsSelected()} onChange={table.getToggleAllRowsSelectedHandler()} /u003e ), cell: ({ row }) =u003e ( u003cinput type=\"checkbox\" checked={row.getIsSelected()} disabled={!row.getCanSelect()} onChange={row.getToggleSelectedHandler()} /u003e ), size: 50, }, // ... 其他列定义 ], []);\// 3. 更新useReactTable配置,启用行选择const [rowSelection, setRowSelection] = useState({}); // 状态管理被选中的行\const table = useReactTable({ data: tableData, columns, state: { rowSelection, // 将行选择状态纳入表格状态管理 }, onRowSelectionChange: setRowSelection, // 状态更新函数 enableRowSelection: true, // 启用行选择功能 getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getSelectedRowModel: getSelectedRowModel(), // 获取被选中行的模型 // ... meta等其他配置});\// 4. 在组件JSX中,添加批量操作按钮区域 eturn ( u003cdiv className=\"table-container\"u003e u003cdiv className=\"table-header\"u003e u003ch2u003e供应链库存明细u003c/h2u003e u003cdivu003e总计: {total} 条记录u003c/divu003e u003c/divu003e {/* 批量操作栏 */} {table.getSelectedRowModel().rows.length u003e 0 u0026u0026 ( u003cdiv className=\"batch-action-bar\"u003e 已选中 {table.getSelectedRowModel().rows.length} 项 u003cbutton onClick={() =u003e alert(`批量设置状态为“冻结”`)}u003e批量冻结u003c/buttonu003e u003cbutton onClick={() =u003e alert(`批量导出选中数据`)}u003e导出选中u003c/buttonu003e u003cbutton onClick={() =u003e table.resetRowSelection()}u003e清空选择u003c/buttonu003e u003c/divu003e )} u003ctableu003e {/* ... 表格渲染代码 */} u003c/tableu003e u003c/divu003e);"}]},{"type":"paragraph","attrs":{"id":"303eed35-dc76-437b-aa7c-eabfcc0dfe58","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"代码解析"},{"type":"text","text":":"}]},{"type":"bulletList","attrs":{"id":"a376c88f-73db-44cd-9736-83a81cad89a5","isHoverDragHandle":false},"content":[{"type":"listItem","attrs":{"id":"a0050618-169e-414a-8c6c-8925dfbc356b"},"content":[{"type":"paragraph","attrs":{"id":"8250c30f-687c-436a-bc7a-81e708ca15a0","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"行选择状态"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"rowSelection"},{"type":"text","text":"状态是一个对象,键为行ID,值为"},{"type":"text","marks":[{"type":"code"}],"text":"true"},{"type":"text","text":"表示被选中。"},{"type":"text","marks":[{"type":"code"}],"text":"onRowSelectionChange"},{"type":"text","text":"用于更新此状态。"}]}]},{"type":"listItem","attrs":{"id":"f83d3fe1-145c-453f-9ea3-5c22d7a792a8"},"content":[{"type":"paragraph","attrs":{"id":"6a65d320-5f43-4f28-babc-b8f7d40e2883","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"选择列定义"},{"type":"text","text":":在"},{"type":"text","marks":[{"type":"code"}],"text":"columns"},{"type":"text","text":"中定义一列,其"},{"type":"text","marks":[{"type":"code"}],"text":"header"},{"type":"text","text":"渲染一个控制全选/全不选的复选框,"},{"type":"text","marks":[{"type":"code"}],"text":"cell"},{"type":"text","text":"为每一行渲染一个复选框。"},{"type":"text","marks":[{"type":"code"}],"text":"table.getToggleAllRowsSelectedHandler()"},{"type":"text","text":"和"},{"type":"text","marks":[{"type":"code"}],"text":"row.getToggleSelectedHandler()"},{"type":"text","text":"是TanStack Table提供的处理函数。"}]}]},{"type":"listItem","attrs":{"id":"b82911a7-e0fc-4155-a9e9-6a762a67560f"},"content":[{"type":"paragraph","attrs":{"id":"c2cd8c09-ce7a-4d80-a496-83c9a3c29e22","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"获取选中行"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"table.getSelectedRowModel().rows"},{"type":"text","text":"可以方便地获取当前选中的所有行数据,用于批量操作。"}]}]}]},{"type":"heading","attrs":{"id":"6b988710-daef-4681-996c-18fd561c6277","textAlign":"inherit","indent":0,"level":1,"isHoverDragHandle":false},"content":[{"type":"text","text":"五、性能优化:虚拟滚动与分页 "}]},{"type":"paragraph","attrs":{"id":"41204b78-dc61-4df7-83c7-7de0e659653c","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"对于超大数据集,一次性渲染所有行会导致严重性能问题。虚拟滚动是终极解决方案。"}]},{"type":"codeBlock","attrs":{"id":"72814fbd-4201-4944-9a6b-5d9914e1ca39","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"# 安装虚拟滚动库
pm install @tanstack/react-virtual"}]},{"type":"codeBlock","attrs":{"id":"51ca7bd4-2c38-4a35-8547-d6fb783bc9f1","language":"javascript","theme":"atom-one-dark","runtimes":0,"isHoverDragHandle":false,"key":"","languageByAi":"javascript"},"content":[{"type":"text","text":"import { useVirtualizer } from '@tanstack/react-virtual';\// 在表格组件中,替换原有的tbody渲染逻辑const tableContainerRef = React.useRef(null);const { rows } = table.getRowModel(); // 获取当前页/排序/筛选后的行\const rowVirtualizer = useVirtualizer({ count: rows.length, getScrollElement: () =u003e tableContainerRef.current, estimateSize: () =u003e 50, // 每行大约高度 overscan: 5, // 过度扫描行数,保证滚动流畅});\// 渲染tbody\u003ctbodyu003e {rowVirtualizer.getVirtualItems().map(virtualRow =u003e { const row = rows[virtualRow.index]; return ( u003ctr key={row.id} style={{ height: `${virtualRow.size}px`, transform: `translateY(${virtualRow.start}px)`, }} u003e {row.getVisibleCells().map(cell =u003e ( u003ctd key={cell.id}u003e {flexRender(cell.column.columnDef.cell, cell.getContext())} u003c/tdu003e ))} u003c/tru003e ); })}\u003c/tbodyu003e"}]},{"type":"paragraph","attrs":{"id":"9c0bdea7-bc69-46d2-bde5-76533e975e88","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"代码解析"},{"type":"text","text":":"},{"type":"text","marks":[{"type":"code"}],"text":"useVirtualizer"},{"type":"text","text":"只渲染视口内的行及其前后少量过度扫描("},{"type":"text","marks":[{"type":"code"}],"text":"overscan"},{"type":"text","text":")的行,而不是全部"},{"type":"text","marks":[{"type":"code"}],"text":"rows"},{"type":"text","text":"。通过"},{"type":"text","marks":[{"type":"code"}],"text":"transform: translateY"},{"type":"text","text":"将行定位到正确的位置。表格容器需要设置固定高度和"},{"type":"text","marks":[{"type":"code"}],"text":"overflow: auto"},{"type":"text","text":"。这是处理万级数据仍保持流畅滚动的关键。"}]},{"type":"paragraph","attrs":{"id":"c445fa32-a12a-4878-80e5-bd82ce5ec85c","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false}},{"type":"heading","attrs":{"id":"daddad37-54d2-4ef4-9339-af0ed0390256","textAlign":"inherit","indent":0,"level":1,"isHoverDragHandle":false},"content":[{"type":"text","text":"结语 "}]},{"type":"paragraph","attrs":{"id":"c7e4a518-3d2d-4afb-a4df-2825818dc027","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"通过本文的详细拆解,我们完成了从零到一,集成 "},{"type":"text","marks":[{"type":"bold"}],"text":"TanStack Table"},{"type":"text","text":" 构建一个功能完备、性能卓越的供应链明细表格。我们不仅实现了基础的数据展示与排序,更深入打造了"},{"type":"text","marks":[{"type":"bold"}],"text":"可编辑单元格"},{"type":"text","text":"、"},{"type":"text","marks":[{"type":"bold"}],"text":"行选择与批量操作"},{"type":"text","text":"等贴合供应链业务的高频交互功能,并借助"},{"type":"text","marks":[{"type":"bold"}],"text":"虚拟滚动"},{"type":"text","text":"技术确保了面对海量数据时的极致流畅体验。"}]},{"type":"paragraph","attrs":{"id":"52a89897-a077-430e-bfa9-33acdb8a0fa2","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"回顾本文核心收获:"}]},{"type":"bulletList","attrs":{"id":"77699bbb-c863-4f81-9bcd-d6dcddf47235","isHoverDragHandle":false},"content":[{"type":"listItem","attrs":{"id":"bcc4a9a5-0cc1-4a92-828e-ec725ee57716"},"content":[{"type":"paragraph","attrs":{"id":"d3310ed9-bee3-4164-8d6a-dce88fe51ebf","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"选型决策力"},{"type":"text","text":":理解了在复杂企业级应用中选择无头(Headless)表格库(如TanStack Table)的必要性,它提供了无与伦比的灵活性、性能和控制力。"}]}]},{"type":"listItem","attrs":{"id":"cee1cc05-ed5f-4f7a-90bf-069dce41ca85"},"content":[{"type":"paragraph","attrs":{"id":"f4ab7390-0372-4281-86af-4a830b60679c","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"架构清晰度"},{"type":"text","text":":掌握了将表格逻辑(状态、排序、选择)与UI渲染分离的架构模式,使组件更易于维护和测试。"}]}]},{"type":"listItem","attrs":{"id":"c5dbe7da-4487-4341-990f-c539cd8a5d61"},"content":[{"type":"paragraph","attrs":{"id":"012ed766-edd3-4525-997d-c52c52f835bd","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"功能实现深度"},{"type":"text","text":":学会了如何利用"},{"type":"text","marks":[{"type":"code"}],"text":"meta"},{"type":"text","text":"对象实现跨组件通信,以优雅的方式完成表格数据的编辑与更新;掌握了通过内置插件快速实现行选择与批量操作逻辑。"}]}]},{"type":"listItem","attrs":{"id":"252a91f5-ab82-425d-8396-d04f4c0dbc13"},"content":[{"type":"paragraph","attrs":{"id":"9b8a64f3-e4c9-40d9-901e-0be27925da94","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"性能优化意识"},{"type":"text","text":":认识到虚拟滚动对于大数据量场景是不可或缺的,并学会了使用"},{"type":"text","marks":[{"type":"code"}],"text":"@tanstack/react-virtual"},{"type":"text","text":"与TanStack Table无缝集成,实现性能的飞跃。"}]}]},{"type":"listItem","attrs":{"id":"c7886f36-0ccb-4751-8fd3-0d3ffd96efb1"},"content":[{"type":"paragraph","attrs":{"id":"422e525f-5324-4a2a-81f1-9718ac6d1556","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"实战组合方案"},{"type":"text","text":":获得了将TanStack Table与React Query(数据获取/缓存)、自定义Hooks(编辑状态)结合使用的完整实战经验。"}]}]}]},{"type":"paragraph","attrs":{"id":"e050b0b2-9fd1-48a5-a5e1-69f4aa36ef14","textAlign":"inherit","indent":0,"color":null,"background":null,"isHoverDragHandle":false},"content":[{"type":"text","text":"至此,你的供应链系统拥有了一颗强大的“数据心脏”。你可以在此基础上,继续探索TanStack Table的"},{"type":"text","marks":[{"type":"bold"}],"text":"列过滤、列拖拽、树形数据展开、服务端分页/排序"},{"type":"text","text":"等高级特性,并结合本系列前述的"},{"type":"text","marks":[{"type":"bold"}],"text":"动态表单、实时同步"},{"type":"text","text":"等能力,构建出真正一体化、响应迅捷的供应链管理平台。"}]}]}











