ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TanStack Table React 中 SubscribePropsWithSource 类型解析:细粒度订阅 Atom 与 Store 的强类型方案

TanStack Table React 中 SubscribePropsWithSource 类型解析:细粒度订阅 Atom 与 Store 的强类型方案 TanStack Table React 中 SubscribePropsWithSource 类型解析细粒度订阅 Atom 与 Store 的强类型方案【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table本篇技术指南围绕 TanStack TableReact 适配层tanstack/react-table公开类型SubscribePropsWithSourceTSourceValue, TSelected展开讲解如何通过sourceselectorchildren三要素订阅单个 Atom 或 Store原样订阅或投影订阅并剖析其与SubscribePropsWithSourceIdentity、SubscribePropsWithSourceWithSelector、SubscribeProps的类型层级关系以及底层useSelector 浅比较的实现原理。读完本文你将掌握在 React 表格中按需订阅table.atoms.rowSelection、table.optionsStore等单一数据源、避免整表重渲染的完整实践方案。一、类型定义一个联合类型的“二选一”SubscribePropsWithSource定义在 react-table/src/Subscribe.ts本质是一个可辨识联合discriminated unionexport type SubscribePropsWithSourceTSourceValue, TSelected TSourceValue | SubscribePropsWithSourceIdentityTSourceValue | SubscribePropsWithSourceWithSelectorTSourceValue, TSelected它对应Subscribe组件的两种调用形态不传selector——命中SubscribePropsWithSourceIdentity原样订阅整个源的值传入selector——命中SubscribePropsWithSourceWithSelector订阅源值的投影结果。官方类型注释明确建议当省略selector时优先直接使用SubscribePropsWithSourceIdentity或SubscribePropsWithSourceWithSelector因为二选一联合在省略selector的场景下类型推断更清晰见 Subscribe.ts:57-61。类型参数参数默认值含义TSourceValue无默认值必填被订阅数据源Atom/Store中存储的值的类型TSelected TSourceValue经过selector投影后 children 实际接收的值的类型注意TSelected的默认值正是TSourceValue当不使用投影时children 拿到的就是源值本身因此不需要单独声明第二个类型参数。二、拆解两个分支变体1. SubscribePropsWithSourceIdentity原样订阅定义见 react-table/src/Subscribe.ts:41-45export type SubscribePropsWithSourceIdentityTSourceValue { source: SubscribeSourceTSourceValue selector?: undefined children: ((state: TSourceValue) ReactNode) | ReactNode }三个关键点sourceSubscribeSourceTSourceValue一个 Atom、只读 Atom、Store 或只读 Storeselector?: undefined被强制声明为undefined从类型层面禁止传入 selectorchildren既可以是接收源值的函数(state: TSourceValue) ReactNode也可以是静态的ReactNode。官方文档对其语义的说明是订阅某个源的完整值例如table.atoms.rowSelection或table.optionsStore省略selector等价于恒等选择器identity selector——children 直接收到TSourceValue见 SubscribePropsWithSourceIdentity.md。2. SubscribePropsWithSourceWithSelector投影订阅定义见 react-table/src/Subscribe.ts:51-55export type SubscribePropsWithSourceWithSelectorTSourceValue, TSelected { source: SubscribeSourceTSourceValue selector: (state: TSourceValue) TSelected children: ((state: TSelected) ReactNode) | ReactNode }与 Identity 形态的唯一区别是selector为必填函数它接收源值TSourceValue返回投影后的TSelected而 children 收到的是TSelected。这一形态适合“数据源很大但只需要其中一小块”的场景例如从整张行选择表中投影出某一行是否被选中。三、source 的合法取值SubscribeSource两种形态共享source字段其类型SubscribeSourceTValue定义在 react-table/src/Subscribe.ts:13-14export type SubscribeSourceTValue | AtomTValue | ReadonlyAtomTValue | StoreTValue | ReadonlyStoreTValue即四种来自tanstack/react-store的响应式数据源均可直接作为source传入类型说明AtomTValue可变原子状态ReadonlyAtomTValue只读原子状态StoreTValue可变存储ReadonlyStoreTValue只读存储在 TanStack Table React 的实际 API 中最常见的两个source就是table.atoms.rowSelectionAtom 形态行选择状态table.optionsStoreStore 形态表格配置项存储。这解释了为什么该类型命名为 “WithSource”——它面向的是单个源atom 或 store而非整个table.store。四、与 SubscribeProps 的关系类型金字塔SubscribePropsWithSource不是孤立的类型它被更大的联合类型SubscribeProps收编Subscribe.ts:66-73export type SubscribeProps TFeatures extends TableFeatures, TSelected unknown, TSourceValue unknown, | SubscribePropsWithStoreTFeatures, TSelected | SubscribePropsWithSourceIdentityTSourceValue | SubscribePropsWithSourceWithSelectorTSourceValue, TSelected也就是说Subscribe组件的完整 props 集合包含三种订阅模式Store 模式SubscribePropsWithStore订阅table.store完整表格状态selector接收完整TableStateTFeatures并必填防止开发者无意中订阅整个 store见 Subscribe.ts:20-34源 Identity 模式本文主题的恒等订阅源投影模式本文主题的投影订阅。本文讨论的SubscribePropsWithSource恰好覆盖其中的后两种。五、底层实现useSelector 浅比较类型层之外Subscribe组件的运行时实现Subscribe.ts:122-149揭示了“为什么细粒度订阅不会引发整树重渲染”export function SubscribeTSourceValue( props: SubscribePropsWithSourceIdentityTSourceValue, ): ReturnTypeFunctionComponent export function SubscribeTSourceValue, TSelected( props: SubscribePropsWithSourceWithSelectorTSourceValue, TSelected, ): ReturnTypeFunctionComponent // ... Store 模式重载 ... export function SubscribeTFeatures extends TableFeatures, TSelected, TSourceValue( props: SubscribePropsTFeatures, TSelected, TSourceValue, ): ReturnTypeFunctionComponent { const selected useSelector( props.source, props.selector as Parameterstypeof useSelector[1], { compare: shallow }, ) as TSelected return typeof props.children function ? (props.children as (state: TSelected) ReactNode)(selected) : props.children }实现要点重载优先源码为三种形态分别声明了函数重载identity、with-selector、store保证 JSX 场景下的上下文类型推断尽可能精确统一的订阅协议Atom 与 Store 共享tanstack/react-store的选择协议所以source可以统一交给useSelector处理代码中仅需对联合参数做一次类型拓宽见 Subscribe.ts:138-141 的注释浅比较shallow compareuseSelector使用compare: shallow只有投影结果的浅比较不等时才会触发重渲染这正是性能收益的来源children 二态分发children是函数时以投影结果为入参调用否则原样渲染静态节点。六、实战用法示例源码注释Subscribe.ts:83-120给出了四种典型写法这里结合本文类型逐一解读。示例 1Identity 形态——整块订阅行选择 Atom// 省略 selector等价于恒等投影 Subscribe source{table.atoms.rowSelection} {(rowSelection) div{Object.keys(rowSelection).length} rows selected/div} /Subscribe命中SubscribePropsWithSourceIdentitychildren 直接拿到rowSelection对象。示例 2投影形态——订阅某一行的选中状态Subscribe source{table.atoms.rowSelection} selector{(rowSelection) rowSelection?.[row.id]} {(selected) tr>Subscribe source{table.store} selector{(state) ({ rowSelection: state.rowSelection })} {({ rowSelection }) ( divSelected rows: {Object.keys(rowSelection).length}/div )} /Subscribe注意此处selector必填Store 模式约束且按浅比较语义返回新对象字面量也符合预期的触发条件。示例 4table.Subscribe——实例方法形态table.Subscribe selector{(state) ({ rowSelection: state.rowSelection })} {({ rowSelection }) ( divSelected rows: {Object.keys(rowSelection).length}/div )} /table.SubscribeuseTable返回的表格实例会把Subscribe绑定为实例方法见 useTable.ts:169-174并自动注入source table.store。源码注释Subscribe.ts:80-82特别提醒如果使用useTable产生的table.Subscribe应优先用这个实例 API——它有更完善的重载JSX 上下文类型推断比独立组件的联合 props 类型更友好。七、何时选用哪种形态决策小结场景推荐形态原因需要 Atom/Store 的完整值SubscribePropsWithSourceIdentity不传 selector类型最简TSelected TSourceValue自动推断只需要源值的一部分/变换结果SubscribePropsWithSourceWithSelector必传 selector投影后按浅比较精确控制重渲染范围订阅整个table.store的状态切片Store 模式SubscribePropsWithStore或直接使用table.Subscribeselector 必填强制显式投影防止订阅整棵状态树从类型设计上可以推断项目刻意用“selector?: undefined”与“selector: fn”两个形态把“要不要投影”编码进了类型系统让误用例如传了 selector 却以为没传在编译期即被拦截这是 TanStack Table React 在订阅 API 上“类型即文档”的体现。更多相关类型可继续参阅 SubscribeProps、SubscribeSource 与 SubscribePropsWithStore或直接阅读完整实现 packages/react-table/src/Subscribe.ts。【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表