标准答案
- 表格页面通常由筛选区、操作区、表格区、分页区和状态反馈组成。
- 查询参数要有单一来源,可以同步到 URL,方便刷新、分享和返回时恢复状态。
- 分页、排序、筛选变化要触发同一套请求流程,并处理 loading、empty、error 和 retry。
- 列配置应支持渲染函数、权限控制、固定列、宽度、对齐和响应式降级。
- 批量操作、行内操作和导出要有权限、选中状态、确认弹窗和失败回滚设计。
题目解析
这道题考的是页面架构,不是表格组件 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 状态仍然散落在页面里。
- 查询条件变化后不重置页码,导致新条件下直接请求不存在的页。
- 没有设计空状态、错误重试和权限隐藏,真实业务场景下体验断裂。