标准答案

  1. 表格页面通常由筛选区、操作区、表格区、分页区和状态反馈组成。
  2. 查询参数要有单一来源,可以同步到 URL,方便刷新、分享和返回时恢复状态。
  3. 分页、排序、筛选变化要触发同一套请求流程,并处理 loading、empty、error 和 retry。
  4. 列配置应支持渲染函数、权限控制、固定列、宽度、对齐和响应式降级。
  5. 批量操作、行内操作和导出要有权限、选中状态、确认弹窗和失败回滚设计。

题目解析

这道题考的是页面架构,不是表格组件 API。通用表格的复杂度主要来自查询状态和业务操作。

URL 同步很重要。没有 URL 状态,用户刷新、返回、复制链接后很容易丢失当前查询上下文。

封装时要保留业务扩展口,不能把所有列、按钮、弹窗和请求都写死在一个巨型组件里。

代码示例

下面用 query state 统一驱动筛选、分页和请求。

TSX
function UsersTablePage() {
  const [query, setQuery] = useState({ keyword: '', page: 1, pageSize: 20 })
  const usersQuery = useQuery({
    queryKey: ['users', query],
    queryFn: () => fetchUsers(query)
  })

  function handleSearch(keyword: string) {
    setQuery(prev => ({ ...prev, keyword, page: 1 }))
  }

  return (
    <>
      <UserFilters keyword={query.keyword} onSearch={handleSearch} />
      <UserTable rows={usersQuery.data?.list ?? []} loading={usersQuery.isLoading} />
      <Pagination value={query.page} onChange={page => setQuery(prev => ({ ...prev, page }))} />
    </>
  )
}

常见误区

  • 只封装表格视觉组件,筛选、分页、排序和 URL 状态仍然散落在页面里。
  • 查询条件变化后不重置页码,导致新条件下直接请求不存在的页。
  • 没有设计空状态、错误重试和权限隐藏,真实业务场景下体验断裂。

作者信息