`SubscribePropsWithSourceWithSelector` 接口详解:从原子或 Store 源订阅投影状态)
前端UI组件【免费下载链接】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点击查看免费下载导读SubscribePropsWithSourceWithSelectorTSourceValue, TSelected是tanstack/octane-table中Subscribe组件的一种 props 形态用于让 Octane 组件从某个状态源TanStack Store 的原子Atom或Store订阅一个投影后的值selector接收源值而children渲染函数接收投影结果TSelected。它支撑了 Octane 表格只让树中需要刷新的节点精确重渲染的细粒度订阅模型是优化大表格性能、实现行选择/分页/过滤等局部响应式 UI 的基础。阅读本文后你将掌握该接口的完整属性签名、与恒等订阅整表订阅两种形态的区别以及它在源码层和真实示例中的用法。该接口定义于 packages/octane-table/src/types.ts是SubscribeProps联合类型三种形态之一本文围绕它展开并结合仓库源码与示例进行纵深讲解。接口定位Subscribe 三种 props 形态中的投影订阅在 Octane 适配器中Subscribe组件以及useTable返回实例上的table.Subscribe可以订阅三类状态源分别对应三种 props 形态见 types.tsProps 形态source 取值selectorchildren 收到典型场景SubscribePropsWithStoreTFeatures, TSelectedtable.store整表扁平 Store必填从TableState投影TSelected只关心分页、过滤等若干状态切片SubscribePropsWithSourceIdentityTSourceValue单个 Atom 或 Store省略恒等投影完整的TSourceValue订阅整个行选择 AtomSubscribePropsWithSourceWithSelectorTSourceValue, TSelected单个 Atom 或 Store必填投影结果TSelected从行选择 Atom 中投影单行选中状态三个接口的完整定义与源码注释见 types.ts其中本接口的关键注释为Subscribe to a projected value from a source (atom or store). The selector receives the source value; children receive the projectedTSelected.而SubscribeProps本身是这三种形态的联合types.tsSubscribe组件的导出类型SubscribeComponent则用重载的可调用类型来表达同一约束types.ts以保证 JSX 调用点处selector回调能获得正确的上下文类型推断。类型参数TSourceValue与TSelected该接口声明了TSourceValue与TSelected两个泛型参数TSourceValue状态源所承载的值的类型即source与selector输入参数的类型。它由source传入的 Atom/Store 推断得出。TSelectedselector的返回类型也就是children渲染函数实际收到的投影值的类型。它由selector函数的返回类型推断得出。值得强调的是重载顺序的用意在 SubscribeComponent 中source 相关重载排在 store 重载之前这样TSourceValue能优先从source推断而无selector的恒等重载被单独拆开SubscribePropsWithSourceIdentity使得省略selector时children收到的是TSourceValue而非退化为unknown。若把selector做成可选参数放在同一个重载上TSelected会默认成unknown丢失推断精度——这是该接口被拆成两个独立形态的根本原因。三个属性逐一拆解接口的完整属性签名如下对应 types.tsexport interface SubscribePropsWithSourceWithSelectorTSourceValue, TSelected { source: SubscribeSourceTSourceValue selector: (state: TSourceValue) TSelected children: ((state: TSelected) OctaneNode) | SubscribeStaticChild }source: SubscribeSourceTSourceValue订阅的目标状态源其类型定义于 types.tsexport type SubscribeSourceTValue AtomTValue | ReadonlyAtomTValue | StoreTValue | ReadonlyStoreTValue也就是说可读可写的Atom、只读的ReadonlyAtom、以及Store/ReadonlyStore均可以作为source。在表格场景中最常用的取值是table.atoms.rowSelection、table.atoms.globalFilter、table.atoms.pagination、table.atoms.columnFilters等按状态切片暴露的只读派生 Atomtable.store整表扁平 Store但本接口更鼓励订阅单一 Atom/Store 做局部投影通过atoms选项传入的外部 Atom例如useCreateAtomRowSelectionState({})创建的实例此时source可以是在表格作用域之外独立存在的共享原子。selector: (state: TSourceValue) TSelected投影函数。它接收source的完整值返回投影后的TSelected。Subscribe的实现会把它传给 TanStack Store 的useSelector因此只有投影结果发生变化时订阅者才会重渲染比较采用浅比较shallow compare因此对象字面量形式的 selector 结果如{ rowSelection: state.rowSelection }在值未变时不会触发多余的重渲染。这一点在实现 Subscribe.tsrx 中有直接印证const selected useSelector( props.source as Parameterstypeof useSelector[0], props.selector as Parameterstypeof useSelector[1], { compare: shallow }, )shallow比较的引入正是为了与上游保持一致对象字面量选择器不会在每次状态通知时都触发重渲染。children: ((state: TSelected) OctaneNode) | SubscribeStaticChildchildren 有两种形态渲染函数render prop(state: TSelected) OctaneNode接收投影后的TSelected并返回 Octane 节点。这是本接口的核心用法——children拿到的不是原始源值而是selector投影后的值。静态子节点SubscribeStaticChild定义于 types.ts可以是ElementDescriptor、字符串、数字、布尔值、null/undefined或只读数组。它保持具体类型而非直接使用OctaneNode当前为unknown是为了让函数形式的 children 仍能获得上下文类型推断。实现中Subscribe.tsrx对 children 做了区分处理函数则用投影后的selected调用之否则原样渲染静态子节点。底层机制useSelectorshallow的订阅协议Subscribe组件被作者用.tsrx文件编写见 Subscribe.tsrx 的头部注释因为它内部调用了 slot 键控的 hookuseSelector编译器会为它在调用点分配渲染 slot。Atom 与 Store 共用同一套选择协议组件首次渲染时useSelector对source执行selector得到TSelected后续当该 Atom/Store 状态变化时TanStack Store 重新计算selector并用shallow与上一次结果比较若投影结果不同则仅重渲染该Subscribe节点及其子树——即重渲染精确落在需要它的树节点上。值得注意的实现细节是SubscribeImpl的函数体接收的是联合类型SubscribeProps但导出的绑定被重新标注为重载可调用类型SubscribeComponentSubscribe.tsrx。这是因为.tsrx的{ … }函数体无法携带前置重载签名TS2384 限制而 JSX 调用点需要的是重载解析能力可调用类型恰好提供这一点。调用点仍然获得按重载的逐项推断只有这一个函数体内部看到联合类型。table.Subscribe与独立Subscribe的差异useTable返回的OctaneTable实例上挂载了预绑定好的table.SubscribeuseTable.tsrxtableInstance.Subscribe ((props: any) ( Subscribe {...props} source{props.source ?? tableInstance.store} / )) as OctaneTableTFeatures, TData, TSelected[Subscribe]关键行为不传source时table.Subscribe自动以table.store作为源此时等价于SubscribePropsWithStore形态必须提供 selector传source单个 Atom/Store时就落到本文所讲的SubscribePropsWithSourceWithSelector带 selector或SubscribePropsWithSourceIdentity不带 selector形态。而独立导出的Subscribe从tanstack/octane-table引入见 index.ts 的export * from ./Subscribe.tsrx没有预绑定的源必须在source中显式传入table.store或某个 Atom。useTable本身还通过第二个参数可选 selector将投影值暴露在table.state上useTable.tsrx并借助createRenderPhaseSource 布局副作用实现渲染阶段暂存、提交后才发布的 commit 语义——但那是整表级别的订阅与本接口的树中局部订阅互补。关于两种读取策略直接读快照 vs. 订阅式读取的取舍可进一步参考 docs/framework/octane/guide/table-state.md。实战示例单行选择投影与行模型局部订阅仓库中的 examples/octane/basic-subscribe/src/main.tsrx 完整演示了本接口的两种典型用法。用法一从行选择 Atom 投影单行状态function RowCheckbox({ row, table }: { row: Rowtypeof features, Person; table: TableInstance }) { // 只订阅该行的选中值切换一行时仅重渲染该行的复选框 table.Subscribe source{table.atoms.rowSelection} // 只订阅 row selection atom selector{(rowSelection) Boolean(rowSelection[row.id])} // 只在该行选择变化时重渲染 {(selected: boolean) IndeterminateCheckbox ariaLabel{Select row ${row.id}} checked{selected} disabled{!row.getCanSelect()} indeterminate{row.getIsSomeSelected()} onChange{row.getToggleSelectedHandler()} /} /table.Subscribe }这正是SubscribePropsWithSourceWithSelector的教科书级场景source是table.atoms.rowSelectionReadonlyAtomRowSelectionStateselector把整个行选择状态投影为Boolean(rowSelection[row.id])的布尔值children渲染函数收到的selected就是投影结果。当用户切换一行时只有该行复选框的订阅节点重渲染而不是整个表格。用法二从 Store 投影分页状态table.Subscribe selector{(state) state.pagination} {(pagination: PaginationState) div classNamecontrols>Subscribe source{table.store} selector{(state) state} {(state: TableStatetypeof features) pre>Subscribe source{externalSelection} selector{(selection) Boolean(selection[1])} children{(selectedValue) { const typed: boolean selectedValue return span{String(typed)}/span }} /这里externalSelection是createAtomRowSelectionState({})创建的外部 AtomTSourceValue推断为RowSelectionStateselector返回boolean于是children收到的selectedValue被断言为boolean且通过编译。这份测试同时覆盖了无 selector 的恒等订阅children 收到RowSelectionState与带 selector 的投影订阅两种重载从类型系统层面保证了本接口的推断契约。使用建议与注意事项先默认、再优化如 docs/framework/octane/guide/table-state.md 所建议useTable默认会选中全部注册状态日常开发先使用默认行为只有当大表格出现可感知的性能问题时再改用table.Subscribe配合本接口做局部订阅。理解状态依赖再订阅basic-subscribe示例的注释提醒很难知道该订阅什么除非你理解内部 API 的每个状态依赖。务必测试并验证订阅确实在你预期的时机重渲染。selector 返回稳定引用由于订阅用shallow比较结果selector 应避免每次返回全新的不等价对象否则可能引发多余重渲染。外部 Atom 是推荐的控制方式在 v9 中需要与应用共享的状态如服务端数据获取中的分页、排序、过滤推荐通过atoms选项传入外部 Atom再用SubscribePropsWithSourceWithSelector在任意需要的位置精确订阅。小结SubscribePropsWithSourceWithSelectorTSourceValue, TSelected是 Octane 表格细粒度响应式模型的基石之一source圈定状态源selector把源值投影为 UI 真正需要的形状children只接收投影结果。它与SubscribePropsWithSourceIdentity恒等订阅、SubscribePropsWithStore整表订阅共同构成Subscribe/table.Subscribe的完整 props 契约其实现建立在 TanStack Store 的useSelectorshallow选择协议之上类型推断则由重载的可调用类型保证。需要深入源码时可依次阅读 packages/octane-table/src/types.ts、packages/octane-table/src/Subscribe.tsrx、packages/octane-table/src/useTable.tsrx并结合 examples/octane/basic-subscribe/src/main.tsrx 与 docs/framework/octane/guide/table-state.md 对照学习。赞分享前端UI组件【免费下载链接】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 Table v9 Octane 适配器的 useTable签名、状态选择器与源码原理深入理解 TanStack Table v9 Octane 适配器的 useTable签名、状态选择器与源码原理 TanStack Table v9 将框架无前端UI组件CANN/docs PR文档翻译技能PR文档翻译Skill 功能描述 检测用户本地仓库的md文档自动翻译成英文文档。支持 非docs目录下的所有md文档 docs目录下排除列表外的md文档前端UI组件TanStack Table Octane 订阅源类型 SubscribeSource 全面解析Atom 与 Store 联合类型的精确定义与实战TanStack Table Octane 订阅源类型 SubscribeSource 全面解析Atom 与 Store 联合类型的精确定义与实战 导读 Su前端UI组件上一篇Nerfies实战指南如何训练你自己的可形变3D模型下一篇Sora2API高级功能深度解析视频Remix与分镜功能的实现原理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考