- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
导读
本文围绕 wp-calypso 仓库中 client/state/active-promotions 模块的官方文档,深入讲解 WordPress.com 前端如何通过 Redux 管理"当前有效促销活动(active promotions)"数据。读者将掌握该模块四个 Action Creator 的用法、全局状态树state.activePromotions的数据结构、以及数据经由 Data Layer 从 WP REST API 落库的完整链路,可直接参考用于理解或扩展 Calypso 状态管理中的类似数据模块。
模块定位:一个纯 Redux 数据模块
ActivePromotions 模块用于管理 WordPress.com 的"有效促销活动"数据,例如促销 ID 列表(如spring_sale)、请求状态与错误状态。它是一个典型的、只读型的数据模块:不包含 UI 组件,职责被拆分为 Actions、Reducer、Selectors 三个标准 Redux 部分,源码位于:
- actions.js:Action Creator 定义
- reducer.js:Reducer 组合与数据落库
- selectors.js:从全局状态读取数据
- init.js:向 Redux store 注册 reducer
- schema.js:items 数据的 JSON Schema 校验
- test:配套单元测试(actions / reducer / selectors)
在 Calypso 的状态架构中,模块通过registerReducer( [ 'activePromotions' ], activePromotionsReducer )(见 init.js)挂载到全局状态树,因此任意业务代码只需 importcalypso/state/active-promotions/init即可保证该 reducer 已被注册。
Actions:与 Redux dispatch 协同的数据操纵入口
官方文档明确指出:Actions 需要与 Redux store 实例的dispatch函数配合使用,用于操纵当前的全局状态。模块共暴露四个 Action Creator,见 actions.js:
| Action Creator | 参数 | 触发的 Action 类型 | 作用 |
|---|---|---|---|
activePromotionsReceiveAction( activePromotions ) | activePromotions: Array(WordPress.com 返回的促销列表) | ACTIVE_PROMOTIONS_RECEIVE | 将获取到的促销数据写入状态树 |
activePromotionsRequestSuccessAction() | 无 | ACTIVE_PROMOTIONS_REQUEST_SUCCESS | 标记本次请求成功 |
activePromotionsRequestFailureAction( error ) | error: string(错误信息) | ACTIVE_PROMOTIONS_REQUEST_FAILURE | 记录请求失败 |
requestActivePromotions() | 无 | ACTIVE_PROMOTIONS_REQUEST | 发起获取促销数据的请求 |
所有 Action 类型常量定义在 client/state/action-types.ts 中,供 reducer 与>import { activePromotionsReceiveAction, activePromotionsRequestSuccessAction, activePromotionsRequestFailureAction, requestActivePromotions, } from 'calypso/state/activePromotions/actions'; dispatch( requestActivePromotions() ); wpcom .activePromotions() .list() .then( ( response ) => { dispatch( activePromotionsRequestSuccessAction() ); dispatch( activePromotionsReceiveAction( response ) ); } ) .catch( ( error ) => { dispatch( activePromotionsRequestFailureAction( error.message ) ); } );
这里wpcom.activePromotions().list()是 wpcom.js 客户端 API 的调用形式。注意:在 Calypso 当前的工程实践中,更推荐的方式是直接dispatch( requestActivePromotions() ),由 Data Layer 统一完成 HTTP 请求与结果分发(详见下文"Data Layer"小节),避免在业务组件里手工处理 Promise。
源码级细节
activePromotionsReceiveAction把数据原样放入 action 对象:{ type: ACTIVE_PROMOTIONS_RECEIVE, activePromotions };requestActivePromotions是无参的零载荷 action:{ type: ACTIVE_PROMOTIONS_REQUEST },它本身不携带数据,只是"通知"状态机进入请求中;- 从源码结构看,
activePromotionsRequestSuccessAction与activePromotionsRequestFailureAction专门服务于"请求生命周期"的状态标记,为 UI 层显示加载/错误反馈提供依据。
Reducer:全局状态树中的数据结构
来自上述 actions 的数据会写入全局状态树的activePromotions节点下,官方文档给出的结构如下:
state.activePromotions = { items: [ 'spring_sale' ], requesting: false, errors: false, };结合 reducer.js 的源码,state.activePromotions实际由三个子 reducer 组合而成,字段语义如下:
| 字段 | 类型 | 默认值 | 更新逻辑 |
|---|---|---|---|
items | Array<string> | [] | 收到ACTIVE_PROMOTIONS_RECEIVE时替换为action.activePromotions |
requesting | boolean | false | ACTIVE_PROMOTIONS_REQUEST置为true;成功/失败后置回false |
error | boolean | false | ACTIVE_PROMOTIONS_REQUEST或成功时置为false;失败时置为true |
关于字段命名需要特别说明:原文档的示例中写的是errors,而实际源码(reducer.js)使用的字段名为error(单数),对应的 Selector 也没有暴露读取该字段的接口;阅读或扩展代码时请以源码为准。
items 的数据健壮性处理
items子 reducer 用withSchemaValidation( itemsSchema, ... )包裹(见 reducer.js),schema 定义在 schema.js:items必须是元素类型为string的数组。当传入数据不满足 schema 时会被过滤兜底。
此外,源码专门处理了一个来自后端的边界情况(reducer.js):
// Sometimes an empty PHP can be serialized as `{}` object, force to array in that case if ( ! Array.isArray( action.activePromotions ) ) { return []; }即:当 PHP 后端把空数据序列化为{}对象而非空数组时,reducer 会将其强制归一为空数组[],避免下游 Selector 因拿到非数组而崩溃。
模块级 reducer 的组装
三个子 reducer 通过combineReducers( { items, requesting, error } )组合,再经由withStorageKey( 'activePromotions', combinedReducer )(reducer.js)打上存储键标记,配合 init.js 中的registerReducer注册到全局 store;withStorageKey来自@automattic/state-utils包,用于在持久化/还原时定位该片段。
Data Layer:请求的真正执行者
模块的 actions.js 顶部引入了calypso/state/data-layer/wpcom/active-promotions(actions.js),这是 Calypso Data Layer 框架的接线点。Data Layer 将 Redux action 与 WP REST API 请求解耦,完整实现位于 client/state/data-layer/wpcom/active-promotions/index.js:
- 请求构造:
requestActivePromotions将ACTIVE_PROMOTIONS_REQUESTaction 翻译为一个 HTTP 请求——GET /me/active-promotions,apiVersion: '1.1'(见 index.js); - 成功处理:
receiveActivePromotions从响应体取出active_promotions字段,依次派发activePromotionsRequestSuccessAction()与activePromotionsReceiveAction( active_promotions )(index.js); - 失败处理:
receiveError将原始错误归一化为Error.message字符串后派发失败 action(index.js); - 注册处理器:通过
dispatchRequest( { fetch, onSuccess, onError } )组装,并用registerHandlers绑定到ACTIVE_PROMOTIONS_REQUEST类型上(index.js)。
由此可见,业务代码只需一句dispatch( requestActivePromotions() ),网络请求、成功/失败分发全部由 Data Layer 托管,这正是原文档示例中被隐去、但在工程实践中真正生效的调用路径。
Selectors:从全局状态安全读取数据
selectors.js 提供三个纯函数选择器,供组件以useSelector/connect方式消费数据:
import { getActivePromotions, hasActivePromotion, isRequestingActivePromotions, } from 'calypso/state/active-promotions/selectors'; // 获取全部有效促销 ID 列表,例如 ['spring_sale'] getActivePromotions( state ); // 判断某个促销是否正处于有效状态 hasActivePromotion( state, 'spring_sale' ); // true / false // 判断是否正在请求中(用于加载态展示) isRequestingActivePromotions( state );getActivePromotions( state )直接返回state.activePromotions.items;hasActivePromotion( state, name )基于getActivePromotions的结果做indexOf( name ) !== -1判断,即"促销名称出现在列表中则视为有效";isRequestingActivePromotions( state )返回state.activePromotions.requesting,可用于在 UI 中显示加载中状态。
每个 Selector 文件顶部同样引入了calypso/state/active-promotions/init(selectors.js),确保在读取时 reducer 一定已注册。
测试与代码质量保障
模块在 test 目录下分别对 actions、reducer、selectors 提供了单元测试:
- test/actions.js:断言各 Action Creator 返回的 action 对象结构;
- test/reducer.js:验证 reducer 对各 action 类型的状态转移(含空对象归一为数组的边界用例);
- test/selectors.js:验证选择器从 fixture 状态中取值的正确性;
- test/fixture/index.js:提供测试用的标准状态快照。
同时,client/state/data-layer/wpcom/active-promotions/test/index.js 覆盖了 Data Layer 侧的成功与失败分发逻辑。这四层测试共同保证了从 action 派发到数据落库再到 selector 读取的整条链路行为可验证、可回归。
小结:如何在业务中接入 ActivePromotions
综合官方文档与源码,接入该模块的推荐姿势为:
import { useSelect } from 'calypso/state'; import { requestActivePromotions } from 'calypso/state/active-promotions/actions'; import { hasActivePromotion, isRequestingActivePromotions } from 'calypso/state/active-promotions/selectors'; // 在组件挂载时发起一次请求(Data Layer 会自动完成 HTTP 与分发) dispatch( requestActivePromotions() ); // 渲染时读取状态 const requesting = useSelect( isRequestingActivePromotions ); const isSpringSale = useSelect( ( state ) => hasActivePromotion( state, 'spring_sale' ) );整体数据流为:dispatch(requestActivePromotions())→ Data Layer 发起GET /me/active-promotions→ 成功派发ACTIVE_PROMOTIONS_REQUEST_SUCCESS+ACTIVE_PROMOTIONS_RECEIVE(或失败派发ACTIVE_PROMOTIONS_REQUEST_FAILURE)→ reducer 更新state.activePromotions.{items, requesting, error}→ Selector 供 UI 消费。这套"Action 触发 / Data Layer 请求 / Reducer 落库 / Selector 读取"的四段式结构,也是 wp-calypso 中几乎所有远程数据模块(如 client/state/plans、client/state/sites)共用的范式,掌握 ActivePromotions 即可举一反三。
- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
相关推荐
深入解析 wp-calypso 当前用户状态模块:Action、Reducer 与 Selector 实战指南
深入解析 wp calypso 当前用户状态模块:Action、Reducer 与 Selector 实战指南 导读 本文以 wp calypso(WordPr
前端CMSwp-calypso 全局状态管理实战指南:模块化 Redux Store、keyedReducer 与状态持久化
wp calypso 全局状态管理实战指南:模块化 Redux Store、keyedReducer 与状态持久化 导读 本文基于 WordPress.com
前端CMSwp-calypso 已安装插件状态管理模块(Installed Plugins)深度解析:Actions、Selectors 与 Reducer 全指南
wp calypso 已安装插件状态管理模块(Installed Plugins)深度解析:Actions、Selectors 与 Reducer 全指南 wp
前端CMS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考