Skip to content

Commit b53b29b

Browse files
authored
Functional and async components API change (#27)
1 parent f8d0acf commit b53b29b

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
- Start Date: 2019-04-08
2+
- Target Major Version: 3.x
3+
- Reference Issues: N/A
4+
- Implementation PR: N/A
5+
6+
# Summary
7+
8+
- Functional components must be written as plain functions
9+
- `{ functional: true }` option removed
10+
- `<template functional>` no longer supported
11+
- Async component must be created via the `createAsyncComponent` API method
12+
13+
# Basic example
14+
15+
``` js
16+
import { h } from 'vue'
17+
18+
const FunctionalComp = props => {
19+
return h('div', `Hello! ${props.name}`)
20+
}
21+
```
22+
23+
``` js
24+
import { createAsyncComponent } from 'vue'
25+
26+
const AsyncComp = createAsyncComponent(() => import('./Foo.vue'))
27+
```
28+
29+
# Motivation
30+
31+
## Simplify Functional Components
32+
33+
In 2.x, functional components must be created using the following format:
34+
35+
``` js
36+
const FunctionalComp = {
37+
functional: true,
38+
render(h) {
39+
return h('div', `Hello! ${props.name}`)
40+
}
41+
}
42+
```
43+
44+
This has the following issues:
45+
46+
- Even when the component needs nothing but the render function, it still needs to use the object with `functional: true`.
47+
48+
- Some options are supported (e.g. `props` and `inject`) but others are not (e.g. `components`). However, users often expect all options to be supported because it looks so similar to a normal stateful component (especially when they use SFC with `<template functional>`).
49+
50+
Another aspect of the problem is that we've noticed some users are using functional components solely for performance reasons, e.g. in SFCs with `<template functional>`, and are requesting us to support more stateful component options in functional components. However, I don't think this is something we should invest more time in.
51+
52+
In v3, the performance difference between stateful and functional components has been drastically reduced and will be insignificant in most use cases. As a result there is no longer a strong incentive to use functional components just for performance, which also no longer justifies the maintenance cost of supporting `<template functional>`. Functional components in v3 should be used primarily for simplicity, not performance.
53+
54+
# Detailed Design
55+
56+
In 3.x, we intend to support functional components **only** as plain functions:
57+
58+
``` js
59+
import { h } from 'vue'
60+
61+
const FunctionalComp = (props, slots) => {
62+
return h('div', `Hello! ${props.name}`)
63+
}
64+
```
65+
66+
- The `functional` option is removed, and object format with `{ functional: true }` is no longer supported.
67+
68+
- SFCs will no longer support `<template functional>` - if you need anything more than a function, just use a normal component.
69+
70+
- The function signature has also changed - `h` is now imported globally. Instead of a render context, props and slots and other values are passed in. For more details on how the new arguments can replace 2.x functional render context, see the [Render Function API Change RFC](https://github.com/vuejs/rfcs/pull/28).
71+
72+
## Runtime Props Validation
73+
74+
Props declaration is now optional (only necessary when runtime validation is needed). To add runtime validation or default values, attach `props` to the function itself:
75+
76+
``` js
77+
const FunctionalComp = props => {
78+
return h('div', `Hello! ${props.name}`)
79+
}
80+
81+
FunctionalComp.props = {
82+
name: String
83+
}
84+
```
85+
86+
## Async Component Creation
87+
88+
With the functional component change, Vue's runtime won't be able to tell whether a function is being provided as a functional component or an async component factory. So in v3 async components must now be created via a new API method:
89+
90+
``` js
91+
import { createAsyncComponent } from 'vue'
92+
93+
const AsyncComp = createAsyncComponent(() => import('./Foo.vue'))
94+
```
95+
96+
The method also supports advanced options:
97+
98+
``` js
99+
const AsyncComp = createAsyncComponent({
100+
factory: () => import('./Foo.vue'),
101+
delay: 200,
102+
timeout: 3000,
103+
error: ErrorComponent,
104+
loading: LoadingComponent
105+
})
106+
```
107+
108+
This will make async component creation a little more verbose, but async component creation is typically a low-frequency use case, and are often grouped in the same file (the routing configuration).
109+
110+
# Drawbacks
111+
112+
- Migration cost
113+
114+
# Alternatives
115+
116+
N/A
117+
118+
# Adoption strategy
119+
120+
- For functional components, a compatibility mode can be provided for one-at-a-time migration.
121+
122+
- For async components, the migration is straightforward and we can emit warnings when function components return Promise instead of VNodes.
123+
124+
- SFCs using `<template functional>` should be converted to normal SFCs.

0 commit comments

Comments
 (0)