Repository navigation
feat(rn): 支持页面 preload 并修复预加载页面生命周期 #2615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
b1dac21
bda4dd2
ffc550b
729a98e
3f527f7
e0afbca
dc929c2
864d062
8eec3b1
8a150de
0c8055f
93578fe
238d57c
d9259ce
0ceb77f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # mpx.preload({ url }) | ||
|
|
||
| 预加载目标页面,提前完成页面创建和渲染,不发生页面跳转。仅支持 React Native 端,使用 React Navigation 7.x Native Stack。 | ||
|
|
||
| ## 用法 {#usage} | ||
|
|
||
| ```js | ||
| // 预加载详情页 | ||
| mpx.preload({ url: '/pages/detail?id=1' }) | ||
|
|
||
| // 需要展示时再跳转 | ||
| mpx.navigateTo({ url: '/pages/detail?id=1' }) | ||
| ``` | ||
|
|
||
| `url`:必填,类型为 `string`,表示目标页面路径,支持相对路径和 query 参数。 | ||
|
|
||
| 无返回值,不提供完成回调或 Promise。调用结束不代表页面或数据已加载完成。 | ||
|
|
||
| ## 注意事项 {#notes} | ||
|
|
||
| - 预加载会提前执行 `onLoad`,但不触发 `onShow/onHide`。正式进入并复用该页面时触发 `onShow`,不重复执行 `onLoad`。 | ||
| - RN 的 `onLoad(query, decodedQuery, isPreload)` 第三个参数表示本次初始化是否发生在预加载阶段;普通打开或入栈后才初始化时为 `false`。前两个参数保持原有含义,分别为原始 query 和解码后的 query。 | ||
| - 预加载与跳转参数不同时,可能仍复用同一实例,业务需自行处理参数变化。建议两次调用使用相同参数。 | ||
| - 也可通过 [redirectTo](./redirectTo.md) 进入同路径的预加载页面并替换当前页;页面参数以本次跳转的 query 为准,不合并预加载参数。 | ||
| - 预加载阶段 `getOpenerEventChannel()` 返回 `undefined`。业务应在正式进入的 `onShow` 中获取本次 `navigateTo` 创建的通道;后续再次显示时保持该通道。重复显示时请避免重复注册;发送消息前需确认接收方已就绪。 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| import { envError, successHandle, failHandle, resolvePath, getFocusedNavigation } from '../../../common/js' | ||
| import { parseUrlQuery as parseUrl } from '@mpxjs/utils' | ||
| import { envError, error, successHandle, failHandle, resolvePath, getFocusedNavigation } from '../../../common/js' | ||
| import { parseUrlQuery as parseUrl, isPreloadSupported } from '@mpxjs/utils' | ||
| import { nextTick } from '../next-tick' | ||
| import { EventChannel } from '../event-channel' | ||
|
|
||
|
|
@@ -38,6 +38,33 @@ function canNavigate (navigation, navigationHelper, type, options) { | |
| return true | ||
| } | ||
|
|
||
| function preload (options = {}) { | ||
| const navigation = getFocusedNavigation() | ||
| if (!isPreloadSupported(navigation)) { | ||
| error('preload: current navigator does not support page preloading') | ||
| return | ||
| } | ||
| if (global.__navigationHelper?.lastSuccessCallback) { | ||
| error('preload: another navigation is in progress') | ||
| return | ||
| } | ||
| if (typeof options.url !== 'string' || !options.url.trim()) { | ||
| error('preload: url must be a non-empty string') | ||
| return | ||
| } | ||
| try { | ||
| const { path, queryObj } = parseUrl(options.url, true) | ||
| if (!path) { | ||
| error('preload: url must contain a page path') | ||
| return | ||
| } | ||
| const finalPath = resolvePath(path, getBasePath(navigation)).slice(1) | ||
| navigation.preload(finalPath, queryObj) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] 预加载页会提前覆盖当前页的状态栏样式 调用 preload 后,目标页的 pageWrapperHOC → MpxNav 会挂载,而 MpxNav 无条件渲染 StatusBar。例如 A 配置 navigationBarTextStyle: 'white'、B 配置 'black',在 A 预加载 B 后,尚未跳转就会被 B 覆盖。针对性测试确认了未聚焦的 B 仍追加 StatusBar;RN 的状态栏属性按组件挂载顺序合并:https://reactnative.dev/docs/statusbar#usage-with-navigator 。 建议让状态栏配置随页面焦点生效,并覆盖多个预加载页面的场景。 |
||
| } catch (e) { | ||
| error(`preload: ${e.message}`) | ||
| } | ||
| } | ||
|
|
||
| function navigateTo (options = {}) { | ||
| const navigationHelper = global.__navigationHelper | ||
| const navigation = getFocusedNavigation() | ||
|
|
@@ -84,6 +111,17 @@ function redirectTo (options = {}) { | |
| const res = { errMsg: `redirectTo:fail ${msg}` } | ||
| failHandle(res, options.fail, options.complete) | ||
| } | ||
| if (isPreloadSupported(navigation)) { | ||
| const state = navigation.getState() | ||
| const preloadedRoute = state.preloadedRoutes.find(route => route.name === finalPath) | ||
| if (preloadedRoute) { | ||
| navigation.reset(Object.assign({}, state, { | ||
| routes: state.routes.map((route, index) => index === state.index ? Object.assign({}, preloadedRoute, { params: queryObj }) : route), | ||
| preloadedRoutes: state.preloadedRoutes.filter(route => route.key !== preloadedRoute.key) | ||
| })) | ||
| return | ||
| } | ||
| } | ||
| navigation.replace(finalPath, queryObj) | ||
| } | ||
| } | ||
|
|
@@ -147,6 +185,7 @@ function reLaunch (options = {}) { | |
| const switchTab = envError('switchTab') | ||
|
|
||
| export { | ||
| preload, | ||
| redirectTo, | ||
| navigateTo, | ||
| navigateBack, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P3] 补齐文档入口及 Skill 同步
新增 preload.md 后,还需要在 docs-vitepress/.vitepress/config.ts 的路由 API 侧边栏添加入口,并同步 .agents/skills/mpx/references/rn/rn-api-reference.md、rn-script-reference.md 及相关索引,说明 preload、onLoad 第三个参数 isPreload,以及 EventChannel 的获取时机。当前 PR 未包含这些更新,文档缺少侧边栏入口,Skill 也无法反映新增能力;这也是仓库 AGENTS.md 要求在同一次改动中同步的内容。