• 开始时间:2019-04-08
  • 目标主要版本:3.x
  • 引用 issue:N/A
  • 实现的 PR:N/A

摘要

函数式组件必须写成普通函数

  • { functional: true } 被移除
  • <temple functional> 不再被支持

异步组件现在必须通过专门的 API 创建

基本范例

  1. import { h } from 'vue'
  2. const FunctionalComp = props => {
  3. return h('div', `Hello! ${props.name}`)
  4. }
  1. import { defineAsyncComponent } from 'vue'
  2. const AsyncComp = defineAsyncComponent(() => import('./Foo.vue'))

动机

简化函数式组件

在 2.x 版本,必须使用一下格式创建函数式组件。

  1. const FunctionalComp = {
  2. functional: true,
  3. render(h) {
  4. return h('div', `Hello! ${props.name}`)
  5. }
  6. }

这会有如下几个问题:

  • 即使组件除了渲染函数其他什么都不需要,它仍然需要使用 functional: true 的对象。
  • 有些选项是被支持的(如 props 和 inject),但其他选项不被支持(如 components)。然而,用户期望所有其他选项都会支持,因为它看起来和普通有状态组件非常相似(特别是当他们使用带有 <templete functional> 的 SFC 时)。

问题的另一方面是,我们注意到一些用户完全(solely)是出于性能的考虑而使用函数式组件,例如,在带有 <templet functional> 的 SFC 的中,还会要求我们在函数式组件中支持更多状态组件选项。然而,我不认为这是我们应该投入更多时间的事情。

在 v3 中,在状态组件和函数式组件在性能差异已经大大降低(drastically reduced),并且在大多数情况下都是微不足道的。因此不再有强烈的动机为了性能而使用功能组件,这也不再是为了支持 <template functional> 的而要付出维护成本的理由。v3 中的函数式组件主要是为了简单,而不是性能。

具体设计

在 3.x 中,我们打算支持作为普通函数的函数式组件:

  1. import { h } from 'vue'
  2. const FunctionalComp = (props, { slots, attrs, emit }) => {
  3. return h('div', `Hello! ${props.name}`)
  4. }
  • functional 选项被移除,也不再长久支持 { functional: true } 的对象格式。
  • SFC 将不再长久支持 ,如果你需要比函数更多的东西,只需要使用普通组件。
  • 函数签名也会有变化:
    • h 现在是全局导入;
    • 该函数接收两个参数:props 和一个暴露了 slot、attrs 和 emit 的上下文对象。这些相当于有状态组件上的有 $ 前缀的东西。

与旧语法的比较

新的函数参数应该提供完全取代 2.x 函数式渲染上下文的能力:

  • propsslots 有同等的价值。
  • datachildren 不再需要了(只需要 propsslots)。
  • listeners 将被包含在 attrs 中。
  • injections 可以被新的 inject API(Composition API 的一部分)替代: ```javascript import { inject } from ‘vue’ import { themeSymbol } from ‘./ThemeProvider’

const FunctionalComp = props => { const theme = inject(themeSymbol) return h(‘div’, Using theme ${theme}) }

  1. - parent 访问将会被移除。这是一些内部用例的逃生舱 —— 在用户代码中,`props` `injections` 应该是首选。
  2. <a name="m7A5C"></a>
  3. ## Props 选项的声明
  4. 为了便于在简单的情况下使用,3.x 的函数式组件不需要申明 prop
  5. ```javascript
  6. const Foo = props => h('div', props.msg)
  1. <Foo msg="hello!" />

在没有明确的 props 申明情况下,第一个 props 参数将包含父类传递给该组件的所有内容。

显式的 props 声明

要添加显式的 props 声明,请将 props 附加到函数本身:

  1. const FunctionalComp = props => {
  2. return h('div', `Hello! ${props.name}`)
  3. }
  4. FunctionalComp.props = {
  5. name: String
  6. }

创建异步组件

新的异步组件 API 在它自己的专用 RFC 中讨论。

缺点

  • 迁移成本

备选方案

N/A

采纳策略

  • 对于函数式组件,可以提供一个兼容模式,用于一次性的迁移。
  • 使用