Skip to content

Commit 49de6de

Browse files
authored
Attribute Fallthrough + Functional Component Updates (#154)
1 parent 8aa7c98 commit 49de6de

File tree

3 files changed

+261
-122
lines changed

3 files changed

+261
-122
lines changed

active-rfcs/0007-functional-async-api-change.md

+44-30
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
- Functional components must be written as plain functions
99
- `{ functional: true }` option removed
1010
- `<template functional>` no longer supported
11-
- Async component must be created via the `createAsyncComponent` API method
11+
- Async component must now be created via a dedicated API method
1212

1313
# Basic example
1414

@@ -21,9 +21,9 @@ const FunctionalComp = props => {
2121
```
2222

2323
``` js
24-
import { createAsyncComponent } from 'vue'
24+
import { defineAsyncComponent } from 'vue'
2525

26-
const AsyncComp = createAsyncComponent(() => import('./Foo.vue'))
26+
const AsyncComp = defineAsyncComponent(() => import('./Foo.vue'))
2727
```
2828

2929
# Motivation
@@ -58,7 +58,7 @@ In 3.x, we intend to support functional components **only** as plain functions:
5858
``` js
5959
import { h } from 'vue'
6060

61-
const FunctionalComp = (props, slots) => {
61+
const FunctionalComp = (props, { slots, attrs, emit }) => {
6262
return h('div', `Hello! ${props.name}`)
6363
}
6464
```
@@ -67,11 +67,47 @@ const FunctionalComp = (props, slots) => {
6767

6868
- SFCs will no longer support `<template functional>` - if you need anything more than a function, just use a normal component.
6969

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).
70+
- The function signature has also changed:
71+
- `h` is now imported globally.
72+
- The function receives two arguments: `props` and a context object that exposes `slots`, `attrs` and `emit`. These are equivalent to their `$`-prefixed equivalents on a stateful component.
7173

72-
## Runtime Props Validation
74+
## Comparison with Old Syntax
7375

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:
76+
The new function arguments should provide the ability to fully replace the [2.x functional render context](https://vuejs.org/v2/guide/render-function.html#Functional-Components):
77+
78+
- `props` and `slots` have equivalent values;
79+
- `data` and `children` are no longer necessary (just use `props` and `slots`);
80+
- `listeners` will be included in `attrs`;
81+
- `injections` can be replaced using the new `inject` API (part of [Composition API](https://vue-composition-api-rfc.netlify.com/api.html#provide-inject)):
82+
83+
``` js
84+
import { inject } from 'vue'
85+
import { themeSymbol } from './ThemeProvider'
86+
87+
const FunctionalComp = props => {
88+
const theme = inject(themeSymbol)
89+
return h('div', `Using theme ${theme}`)
90+
}
91+
```
92+
93+
- `parent` access will be removed. This was an escape hatch for some internal use cases - in userland code, props and injections should be preferred.
94+
95+
## Optional Props Declaration
96+
97+
To make it easier to use for simple cases, 3.x functional components do not require `props` to be declared:
98+
99+
```js
100+
const Foo = props => h('div', props.msg)
101+
```
102+
``` html
103+
<Foo msg="hello!" />
104+
```
105+
106+
With no explicit props declaration, the first argument `props` will contain everything passed to the component by the parent.
107+
108+
## Explicit Props Declaration
109+
110+
To add explicit props declarations, attach `props` to the function itself:
75111

76112
``` js
77113
const FunctionalComp = props => {
@@ -85,27 +121,7 @@ FunctionalComp.props = {
85121

86122
## Async Component Creation
87123

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).
124+
The new async component API is discussed in [its own dedicated RFC](https://github.com/vuejs/rfcs/pull/148).
109125

110126
# Drawbacks
111127

@@ -119,6 +135,4 @@ N/A
119135

120136
- For functional components, a compatibility mode can be provided for one-at-a-time migration.
121137

122-
- For async components, the migration is straightforward and we can emit warnings when function components return Promise instead of VNodes.
123-
124138
- SFCs using `<template functional>` should be converted to normal SFCs.

active-rfcs/0010-optional-props-declaration.md

-92
This file was deleted.

0 commit comments

Comments
 (0)