正文
columns
,
setColumns
]
=
useState
(
initColumns
)
...
}
到了 2026 年,客户的业务拓展到了国际市场,有了新的需求。他们开始收集更多订单属性,比如货币、国家等,同时希望用户可以自定义表格列的显示。你添加了一个设置按钮(⚙)在表头旁边,用户点击后可以选择要显示哪些列。
由于可见列是可变的,不能再写成常量,所以你需要用状态来存储它们。并且这个状态要被多个组件共享(比如 OrdersList 和设置按钮组件),为了避免 props 层层传递,你使用了 React 的 Context(ColumnsCtx)来存储列状态。当然你也可以用
Zustand
、Jotai、Redux 或 URL 参数,原理一样。状态初始化使用默认列数组。
2027 年:筛选功能
function Filters(){
const [filters] = useContext(FiltersCtx)
return filters.map(filter=>(
<Filter filter={filter}/>
))
}
function OrdersList(){
const [columns] = useContext(ColumnsCtx)
const [filters] = useContext(FiltersCtx)
const orders = useOrders(columns, filters)
return <Table data={orders}/>
}
type Filters = Array<{
attribute: string,
operator?:'='|'>'|',
values?: Array<string|number>
}>
function FiltersProvider(){
const [filters, setFilters] = useState()
...
}
到 2027 年,客户的订单量迅速增长,用户需要按列值来筛选数据。你新增了 Filters 组件,实现筛选功能。跟列一样,筛选项也是动态变化的,无法写死,且需要多个组件访问,因此你用 FiltersCtx 上下文来管理它。
筛选的逻辑是:用户在筛选组件中选择条件(例如客户名为 Ondrej),组件会调用状态更新函数,更新 FiltersCtx 中的值,从而触发 OrdersList 的重新渲染,useOrders hook 会根据新条件重新获取数据。
状态初始化
你尝试运行代码,却发现筛选项不显示。为什么?因为 FiltersCtx 默认是空的。你需要给它一个初始值。
const initColumns =[
{attribute: