
前端CMS【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址https://gitcode.com/gh_mirrors/wp/wp-calypso点击查看免费下载本篇技术指南围绕 wp-calypso 仓库中的packages/state-utils包展开完整解读 State Utils 包 README 所描述的“从 Calypso 中逐步提取出来的 Redux 状态工具集”。读完本文你将掌握该包四个核心工具createSelector、extendAction、getInitialState、withStorageKey的 API 契约、参数语义与底层实现原理并能在自己的 Redux 应用中写出带缓存的状态选择器、可组合的 action creator 与可持久化的 reducer。包定位与导出结构包级 README 对该包的定位只有一句话这是一个 Redux 状态工具集合其中各工具是从 Calypso即 wp-calypso 的client/主应用中随时间逐步提取出来的第一个被提取的就是create-selector。虽然 README 本身极为简短但 package.json 与 入口文件 给出了包的完整面貌npm 包名为automattic/state-utils描述为 A collection of Redux state utilities当前版本1.0.0-alpha.4许可证GPL-2.0-or-later通过maindist/cjs/index.js、moduledist/esm/index.js与exports字段同时提供 CommonJS 与 ESM 两种产物并通过calypso:src条件直接指向src/index.ts源码供 Calypso 主应用在构建时直接消费 TypeScript 源码运行时依赖包括redux、redux-thunk、automattic/js-utils提供memoize与merge、wordpress/is-shallow-equal与wordpress/warning这些依赖恰好对应四个工具的实现所需。入口文件 共四行导出了包的全部公开 APIexport { default as createSelector } from ./create-selector; export { default as extendAction } from ./extend-action; export { default as getInitialState } from ./get-initial-state; export { default as withStorageKey } from ./with-storage-key;构建方面package.json的 scripts 显示包使用 TypeScript 的 project references 模式yarn build等价于tsc --build ./tsconfig.json ./tsconfig-cjs.json分别产出 ESM/类型与 CJS 两种产物prepack在发布前先执行clean再构建。下面按工具逐一展开。createSelector带依赖追踪的记忆化状态选择器API 契约create-selector 的模块 README 明确了该工具导出一个函数用于创建“记忆化的状态选择器”memoized state selector。它接受三个参数selector 函数从 state 中选取数据。给定 state 对象和任意多个额外参数后计算结果结果会被缓存以供复用getDependants返回该选择器所依赖的 state 树片段。可以是一个函数也可以是“返回状态值数组”的函数数组可选getCacheKey自定义内部记忆化函数所使用的缓存 key 的函数。模块 README 给出的经典场景是state 中存放 post 对象每个 post 属于某个站点要取某站点的全部 post 就需要过滤所有已知 post这是一次昂贵操作。用createSelector可以创建记忆化函数避免重复计算export const getSitePosts createSelector( ( state, siteId ) state.posts.filter( ( post ) post.site_ID siteId ), ( state ) [ state.posts ] );使用时只需关心第一个函数的签名const sitePosts getSitePosts( state, siteId );只要state.posts保持不变该结果就只会被计算一次。实现原理缓存如何被判定与击穿源码实现 揭示了 README 中 FAQ 各问题的答案。默认缓存 key 的生成L36-L52默认的getCacheKey就是对参数调用Array.prototype.join拼成字符串——这正是 README 中“内部记忆化函数通过简单的Array.prototype.join计算缓存 key因此参数不应是复杂对象”的出处。值得注意的是生产/开发环境的分支处理if ( production process.env.NODE_ENV ) { return ( _: unknown, ...args: unknown[] ) args.join(); } return ( _: unknown, ...args: unknown[] ) { const hasInvalidArg args.some( ( arg ) { return arg ! VALID_ARG_TYPES.includes( typeof arg ); } ); if ( hasInvalidArg ) { warn( Do not pass complex objects as arguments for a memoized selector ); } return args.join(); };其中VALID_ARG_TYPES被定义为[ number, boolean, string ]L13。也就是说开发环境下传入对象、数组等复杂参数只会触发wordpress/warning的警告而不改变行为生产环境则直接跳过检查以降低开销。依赖追踪与缓存清除L90-L112返回的选择器闭包持有lastDependants每次调用时先求出当前依赖值若依赖不再是isShallowEqual浅相等于上一次的依赖则调用memoizedSelector.cache.clear()整体清缓存。这与 README FAQ “记忆化选择器如何知道何时重新计算”的回答一致因为 Redux 禁止直接 mutate state依赖片段只要严格不相等即可判定为“已变化”。当getDependants传入数组形式时makeSelectorFromArray 会将其合并为一个函数逐个调用后返回结果数组——这正是 README 中“新选择器依赖多个既有选择器时可以简写为[ foo, bar, baz ]数组”的底层机制。内部缓存的暴露返回函数通过Object.assign挂载了memoizedSelector属性其.cache是一个Map由automattic/js-utils的memoize提供。README FAQ 说明“你极少需要这么做但可以管理返回函数memoizedSelector属性上暴露的.cache一个Map”——这在实际用途上主要是测试中清空缓存。测试用例验证的三条行为边界create-selector 的测试 用真实的选择器构造state state.posts覆盖了 README 承诺的全部行为缓存命中对同一state与同一siteId连续调用两次原始 selector 只执行一次expect( selector ).toHaveBeenCalledTimes( 1 )开发模式警告依次传入1、、foo、true、null、undefined、{}、[]、(1, [])期望warn恰好被调用 3 次对应{}、[]和(1, [])中的数组验证了VALID_ARG_TYPES白名单逻辑缓存击穿当被监视的state.posts变化后再次调用selector 重新执行并得到新结果验证了isShallowEqual失配时cache.clear()的链路。每个用例间通过getSitePosts.memoizedSelector.cache.clear()清理内部Map印证了 README 所述缓存访问方式的真实使用场景。extendAction复用既有 action creator 并注入额外数据模块 README 说明extendAction( action, data )的用途借助既有 action creator 的行为把它派发出去的 action 用给定的 data 对象扩展。使用这个 helper 可以避免重复原始逻辑也不会把新的通常是可选的需求耦合进原始 action creator。它等价于对纯对象 action creator 的结果调用Object.assign但额外支持 action thunk。README 中的示例function original() { return ( dispatch ) { dispatch( { type: example } ); dispatch( { type: example } ); }; } function extended() { return extendAction( original(), { extended: true } ); } dispatch( extended() ); // Dispatches two actions { type: example, extended: true }实现源码 只有两分支非 thunk普通 action 对象return merge( {}, action, data )即用automattic/js-utils的merge做浅层合并返回新对象L23-L25thunk 函数返回一个新 thunk内部构造newDispatch对原始 thunk 中每次dispatch( a )的动作都再套一层extendAction( a, data )然后以newDispatch替换原始dispatch调用原 thunkgetState与其余 extra 参数原样透传L27-L34。源码注释中还指向了client/state/utils/with-enhancers作为“更高级的替代方案”说明该工具在整个 Calypso 状态体系中有清晰的谱系。getInitialState 与 withStorageKey两个轻量级 reducer 工具这两个工具没有独立的模块 README其全部契约体现在 源码 与 源码 中实现都极为精简。getInitialStateget-initial-state/index.tsexport default function getInitialState TState ( reducer: Reducer TState ): TState { return reducer( undefined, { type: calypso/INIT } ); }它利用 Redux reducer 的约定——以undefined作为 state 调用时应返回初始状态——通过派发一个calypso/INIT类型的假 action 取出 reducer 的初始状态。从命名空间前缀calypso可以推断该类型名被特意避开防止与真实 action 冲突。典型用途是在不构建整个 store 的情况下获取某个 slice 的默认初始值例如测试或初始化逻辑。withStorageKeywith-storage-key/index.tsconst withStorageKey T extends Reducer ( storageKey: string, reducer: T ): StorageKeyReducer T { ( reducer as StorageKeyReducer T ).storageKey storageKey; return reducer as StorageKeyReducer T ; };它只是一个给 reducer 附加storageKey字符串属性的包装器TypeScript 层面通过StorageKeyReducer类型把该属性并入类型。结合仓库中的真实用法例如 client/state/a8c-for-agencies/reducer.jsexport default withStorageKey( a8cForAgencies, combinedReducer );client/state/account/reducer.js 同理使用withStorageKey( account, combinedReducer )。从源码结构看storageKey是 Calypso 状态持久化hydration/persistence机制的约定标记上层持久化逻辑遍历各 slice reducer 时通过读取storageKey属性确定该 slice 在存储中的键名从而实现“只有声明了 storageKey 的 slice 才会被持久化”的按需存储。测试与工程化配置包的单元测试由 Jest 驱动配置位于 jest.config.js测试文件与各工具源码同目录放置于test/子目录如 create-selector/test/index.js、extend-action/test/index.ts、with-storage-key/test/index.ts。类型检查与产物构建依赖 tsconfig.json 与 tsconfig-cjs.json 两个 TypeScript 工程配置继承自automattic/calypso-typescript-configworkspace 依赖保证与整个 monorepo 一致的编译选项。小结与适用前提createSelector适用于“state 保持最小冗余、但派生计算昂贵”的场景参数必须保持为number/boolean/string等简单值复杂对象在开发环境会告警多依赖场景可用选择器数组简写缓存可通过memoizedSelector.cache这个Map手动管理extendAction适用于在不改动原始 action creator 的前提下为普通 action 或 thunk 统一注入额外字段是Object.assign的 thunk 安全版本getInitialState用calypso/INIT假 action 探测 reducer 初始状态withStorageKey为 reducer 打持久化标记是 Calypso 中大量 slice如account、a8cForAgencies参与状态持久化的入口。需要注意的适用前提该包版本为1.0.0-alphaAPI 仍可能演进createSelector的缓存以“依赖片段浅比较 参数join拼 key”为基础依赖比较是浅比较深层嵌套变化需由上层 slice 以不可变更新暴露为引用变化才能正确触发缓存击穿。赞分享前端CMS【免费下载链接】wp-calypsoThe JavaScript and API powered WordPress.com项目地址https://gitcode.com/gh_mirrors/wp/wp-calypso点击查看免费下载相关推荐wp-calypso 中的 automattic/shopping-cartWordPress.com 购物车的 React 状态管理方案全解wp calypso 中的 automattic/shopping cartWordPress.com 购物车的 React 状态管理方案全解 wp cal前端CMSwp-calypso 中 automattic/calypso-babel-config 的配置体系与 importSource 动态化改造解析wp calypso 中 automattic/calypso babel config 的配置体系与 importSource 动态化改造解析 这篇技术指南前端CMSwp-calypso Site Sync 状态管理从 State 树到 SITE_SYNC_STATUS 状态机全解析wp calypso Site Sync 状态管理从 State 树到 SITE_SYNC_STATUS 状态机全解析 导读 Site Sync站点同步是前端CMS上一篇GitHub_Trending/cr/create-t3-turbo聊天功能实时消息与聊天界面设计下一篇TVBoxOSC 快速上手指南3 步让电视盒子完成在线播放与片源管理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考