- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
<QuerySiteConnectionStatus />是 wp-calypso(WordPress.com 的 JavaScript 与 API 驱动型前端)中用于自动发起网络请求、获取 Jetpack 站点与 WordPress.com 连接状态的数据查询组件。它不渲染任何 DOM,只负责把 Redux 全局状态树中的数据准备好,供同级兄弟组件消费。读完本文,你将掌握该组件的用法、props 契约、底层 Redux 数据流(action → reducer → selector)以及对应单元测试的验证方式,可直接在自有 Calypso 区块中落地复用。
组件定位:数据查询组件(Query Component)设计模式
在 wp-calypso 的client/components/data/目录下,存在一系列以Query前缀命名的组件,它们遵循统一的“查询组件”设计模式:渲染即发起请求,无渲染输出,数据写入全局状态树。
QuerySiteConnectionStatus正是该模式在“站点连接状态”场景下的实现,其完整源码位于 client/components/data/query-site-connection-status/index.jsx。从源码结构看,该组件是一个典型的函数式组件,核心逻辑只有三件事:
- 通过
useSelector之外的方式(这里直接使用getState)读取当前是否已在请求该站点的连接状态; - 若尚未在请求,则派发
requestConnectionStatus( siteId )action; - 返回
null,即不渲染任何元素。
// client/components/data/query-site-connection-status/index.jsx(节选) const request = ( siteId ) => ( dispatch, getState ) => { if ( siteId && ! isRequestingSiteConnectionStatus( getState(), siteId ) ) { dispatch( requestConnectionStatus( siteId ) ); } }; export default function QuerySiteConnectionStatus( { siteId } ) { const dispatch = useDispatch(); useEffect( () => { dispatch( request( siteId ) ); }, [ dispatch, siteId ] ); return null; }关键设计点:
- 副作用收敛在
useEffect中:siteId变化会重新触发请求,因此切换站点时组件会自动拉取新站点的连接状态; - 幂等防重:
isRequestingSiteConnectionStatus守卫保证了同一站点在请求进行中不会被重复发起请求; - 无渲染:组件返回
null,页面布局完全不受影响,与兄弟组件解耦。
使用方式:渲染即触发请求
按官方 README(client/components/data/query-site-connection-status/README.md)的说明,使用该组件只需渲染它并传入siteId。它不接受任何 children,也不向页面渲染任何元素,你可以把它与依赖全局状态中已获取数据的兄弟组件并排使用:
import QuerySiteConnectionStatus from 'calypso/components/data/query-site-connection-status'; export default function ExampleSiteComponent( { siteConnectionStatus, translate } ) { return ( <div> <QuerySiteConnectionStatus siteId={ 12345678 } /> { siteConnectionStatus ? translate( 'Site is connected' ) : translate( 'Site is not connected' ) } </div> ); }Props 契约
| Prop | 类型 | 必填 | 说明 |
|---|---|---|---|
siteId | Number | 是 | 需要获取 WordPress.com 连接状态的站点 ID |
该契约同样在组件源码中通过 PropTypes 声明(PropTypes.number.isRequired),缺失siteId会在开发环境抛出 PropTypes 警告。
底层数据流:从 action 到 Redux 状态
组件本身只是“触发器”,真正的数据获取由client/state/site-connection/模块完成。整体数据流为:
渲染 QuerySiteConnectionStatus(siteId) │ ▼ dispatch(requestConnectionStatus(siteId)) // actions.js │ ▼ SITE_CONNECTION_STATUS_REQUEST // 标记 requesting[siteId] = true │ ▼ GET /rest/v1.1/jetpack-blogs/{siteId}/test-connection │ ├── 成功 ──► SITE_CONNECTION_STATUS_RECEIVE + REQUEST_SUCCESS └── 失败 ──► SITE_CONNECTION_STATUS_REQUEST_FAILURE │ ▼ reducer 更新 state.siteConnection.{items, requesting} │ ▼ selector 读取(getSiteConnectionStatus / isRequestingSiteConnectionStatus)Action:请求连接状态
client/state/site-connection/actions.js 中的requestConnectionStatus( siteId )是一个 Redux thunk,它:
- 先派发
SITE_CONNECTION_STATUS_REQUEST标记请求开始; - 通过
wp.req.get( '/jetpack-blogs/${ siteId }/test-connection' )调用 WordPress.com REST API 的test-connection端点; - 成功后派发
SITE_CONNECTION_STATUS_RECEIVE(携带response.connected布尔值)与SITE_CONNECTION_STATUS_REQUEST_SUCCESS; - 失败时派发
SITE_CONNECTION_STATUS_REQUEST_FAILURE(携带 error)。
export const requestConnectionStatus = ( siteId ) => { return ( dispatch ) => { dispatch( { type: SITE_CONNECTION_STATUS_REQUEST, siteId } ); return wp.req .get( `/jetpack-blogs/${ siteId }/test-connection` ) .then( ( response ) => { dispatch( { type: SITE_CONNECTION_STATUS_RECEIVE, siteId, status: response.connected } ); dispatch( { type: SITE_CONNECTION_STATUS_REQUEST_SUCCESS, siteId } ); } ) .catch( ( error ) => { dispatch( { type: SITE_CONNECTION_STATUS_REQUEST_FAILURE, siteId, error } ); } ); }; };Reducer:状态如何落库
client/state/site-connection/reducer.js 通过combineReducers组合了两个子 reducer,最终挂载到全局状态树的state.siteConnection键(注册逻辑见 client/state/site-connection/init.js):
items:以siteId为键存储连接状态布尔值。收到SITE_CONNECTION_STATUS_RECEIVE时写入[siteId]: status;同一站点重复接收时覆盖旧值,不同站点则累积(实现为不可变展开...state)。requesting:以siteId为键标记请求进行中状态。REQUEST置true,REQUEST_SUCCESS/REQUEST_FAILURE置false。
Selector:兄弟组件如何消费数据
数据落地后,业务组件通过 selector 读取:
- client/state/selectors/get-site-connection-status.js:返回
state.siteConnection.items[ siteId ] ?? null。站点未知或尚未收到状态时返回null,收到后返回布尔值。这正是上方示例中siteConnectionStatus的数据来源; - client/state/selectors/is-requesting-site-connection-status.js:返回
state.siteConnection.requesting[ siteId ] ?? false,用于组件内的防重判断。
测试验证:行为被单元测试完整锁定
该模块的测试覆盖了 action 与 reducer 两个层面,是理解组件行为的权威佐证。
Action 测试
client/state/site-connection/test/actions.js 使用useNockmock REST 请求,验证了三种行为:
- 发起时:派发
SITE_CONNECTION_STATUS_REQUEST; - 成功时:依次派发
SITE_CONNECTION_STATUS_RECEIVE(status 为true)与SITE_CONNECTION_STATUS_REQUEST_SUCCESS,mock 的响应体形如{ connected: true, message: 'User is connected.' }; - 失败时:派发
SITE_CONNECTION_STATUS_REQUEST_FAILURE,其中 error 的 message 为接口返回的'This user is not authorized to test connection for this blog.'(对应 403 场景)。
这从侧面印证了接口契约:test-connection端点返回connected布尔字段,未授权用户会收到 403。
Reducer 测试
client/state/site-connection/test/reducer.js 使用deepFreeze保证不可变性,验证了:
items默认空对象、写入、多站点累积、同站点覆盖四种行为;requesting默认空对象、置true、成功后置false、失败后置false四种行为。
实战建议与注意事项
- 配合 selector 使用:组件只负责触发请求,展示逻辑应通过
getSiteConnectionStatus等 selector 从 Redux 状态树读取,避免在渲染层直接持有请求结果; siteId必须有效:源码中request对siteId做了 truthy 判断,空值不会发起请求;PropTypes 亦要求必填,建议在渲染前确保站点对象已就绪;- 请求状态区分:
null(未知/未请求)与false(已确认未连接)语义不同,界面上的“加载中 / 未连接”态应分开处理; - 只读使用:该组件仅用于在页面中触发数据获取,无需(也不应)直接修改仓库中的 Redux 模块。
小结
QuerySiteConnectionStatus是 wp-calypso 查询组件模式的精炼示例:无渲染、副作用收敛、幂等防重,配合client/state/site-connection/的 action/reducer/selector 三层结构,将 Jetpack 站点的 WordPress.com 连接状态查询无缝接入全局状态管理。理解它的完整链路(组件 → action → reducer → selector)之后,你可以轻松类比到client/components/data/下的其他查询组件,快速上手 Calypso 的数据获取体系。
- 前端
- CMS
【免费下载链接】wp-calypso
The JavaScript and API powered WordPress.com
相关推荐
深入解析 wp-calypso 的 `<QueryJetpackConnection />`:Jetpack 站点连接状态的声明式数据获取组件
深入解析 wp calypso 的 <QueryJetpackConnection / :Jetpack 站点连接状态的声明式数据获取组件 导读 <QueryJ
前端CMSwp-calypso 数据查询组件深度解析:QuerySiteProducts 站点产品数据获取实战指南
wp calypso 数据查询组件深度解析:QuerySiteProducts 站点产品数据获取实战指南 <QuerySiteProducts / 是 Word
前端CMSwp-calypso 中 QueryJetpackProductInstallStatus 组件解析:Jetpack 产品安装状态的数据查询实践
wp calypso 中 QueryJetpackProductInstallStatus 组件解析:Jetpack 产品安装状态的数据查询实践 <QueryJ
前端CMS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考