- 开始时间:2020-03-25
- 目标主要版本:3.x
- 引用 issue:https://github.com/vuejs/rfcs/pull/28
- 实现的 PR:N/A
摘要
引入一个专门的 API 来定义异步组件。
基本范例
import { defineAsyncComponent } from "vue"// simple usageconst AsyncFoo = defineAsyncComponent(() => import("./Foo.vue"))// with optionsconst AsyncFooWithOptions = defineAsyncComponent({loader: () => import("./Foo.vue"),loadingComponent: LoadingComponent,errorComponent: ErrorComponent,delay: 200,timeout: 3000})
动机
根据 RFC-0008:渲染函数的 API 变化中引入的变化,在 Vue3 中,普通函数现在被视为函数式组件。异步组件现在必须通过 API 方法明确定义。
具体设计
简单的用法
import { defineAsyncComponent } from "vue"// simple usageconst AsyncFoo = defineAsyncComponent(() => import("./Foo.vue"))
definedAsyncComponent 可以接受一个 loader 函数,该函数返回一个解析为真实组件的 Promise。
- 如果 resolved 的值是一个 ES 模块,该模块的
default导出将被自动用作组件。 - 与 2.x 的区别:请注意,loader 函数不再像 2.x 中那样接收
resolve和reject参数 —— 必须始终返回一个 Promise。
对于在 loader 函数中依赖自定义 resolve 和 reject 的代码,转换很简单: ```javascript // before const Foo = (resolve, reject) => { / … / }
// after const Foo = defineAsyncComponent(() => new Promise((resolve, reject) => { / … / }))
<a name="KcFTw"></a>## 选项的用法```javascriptimport { defineAsyncComponent } from "vue"const AsyncFooWithOptions = defineAsyncComponent({loader: () => import("./Foo.vue"),loadingComponent: LoadingComponent,errorComponent: ErrorComponent,delay: 100, // default: 200timeout: 3000, // default: Infinitysuspensible: false, // default: trueonError(error, retry, fail, attempts) {if (error.message.match(/fetch/) && attempts <= 3) {retry()} else {fail()}}})
delay和time选项的工作方式和 2.x 中一样
与 2.x 的区别:
component选项被新的loader选项替换了,它接受与简单用法中相同的 loader 函数。
在 2.x 中,一个带有选项的异步组件被定义为:() => ({component: Promise<Component>// ...other options})
而到了 3.x 中是这样:
defineAsyncComponent({loader: () => Promise<Component>// ...other options})
2.x 的
loader和error选项分别被重新命名为 loadingComponent 和 errorComponent,含义更加清晰。
重试控制
新的 onError 选项提供了一个钩子,在 loader 出错的情况下执行自定义的重试行为:
const Foo = defineAsyncComponent({// ...onError(error, retry, fail, attempts) {if (error.message.match(/fetch/) && attempts <= 3) {// retry on fetch errors, 3 max attemptsretry()} else {fail()}}})
注意,retry/fail 就像 promise 的 resolve/reject 一样:必须调用其中之一才能继续处理错误。
与 Suspense 一起使用
在 3.x 中的异步组件默认是可以 suspensible(挂起) 的。这意味着如果它在父元素链中有一个 loading、error、delay 和 timeout 选项将被忽略。
异步组件可以通过在选项中指定 suspensible: false 来选择退出 Suspense 的控制,让组件始终控制自己的 loading 状态。
缺点
N/A
备选方案
N/A
采纳策略
- 语法转换是机械的,可以空过 codemod 进行。挑战在于确定哪些普通函数应该被视为异步组件。可以使用一些基本的启发式方法:
- 返回动态
import调用.vue文件的箭头函数。 - 箭头函数返回一个对象,其
component属性是一个动态的import调用。
- 返回动态
注意,这可能不包括 100% 的现有情况。
- 在 compat 构建中,可以检查函数式组件的返回值并警告传统的异步组件使用方式。这应该涵盖所有基于 Promise 的用例。
- 唯一不能轻易检测的情况是 2.x 的异步组件使用手动 resolve/reject 而不是返回 promise。这种情况需要手动升级,但应该比较少。
没有解决的问题
N/A
