# Composition
# mixins
Type:
Array<Object>
Details:
The
mixins
option accepts an array of mixin objects. These mixin objects can contain instance options like normal instance objects, and they will be merged against the eventual options using the certain option merging logic. For example, if your mixin contains acreated
hook and the component itself also has one, both functions will be called.Mixin hooks are called in the order they are provided, and called before the component's own hooks.
INFO
In Vue 2, mixins were the primary mechanism for creating reusable chunks of component logic. While mixins continue to be supported in Vue 3, the Composition API is now the preferred approach for code reuse between components.
Example:
const mixin = { created() { console.log(1) } } createApp({ created() { console.log(2) }, mixins: [mixin] }) // => 1 // => 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15See also: Mixins
# extends
Type:
Object
Details:
Allows one component to extend another, inheriting its component options.
From an implementation perspective,
extends
is almost identical tomixins
. The component specified byextends
will be treated as though it were the first mixin.However,
extends
andmixins
express different intents. Themixins
option is primarily used to compose chunks of functionality, whereasextends
is primarily concerned with inheritance.As with
mixins
, any options will be merged using the relevant merge strategy.Example:
const CompA = { ... } const CompB = { extends: CompA, ... }
1
2
3
4
5
6
# provide / inject
Type:
- provide:
Object | () => Object
- inject:
Array<string> | { [key: string]: string | Symbol | Object }
- provide:
Details:
This pair of options are used together to allow an ancestor component to serve as a dependency injector for all its descendants, regardless of how deep the component hierarchy is, as long as they are in the same parent chain. If you are familiar with React, this is very similar to React's
context
feature.The
provide
option should be an object or a function that returns an object. This object contains the properties that are available for injection into its descendants. You can use ES2015 Symbols as keys in this object, but only in environments that natively supportSymbol
andReflect.ownKeys
.The
inject
option should be either:- an array of strings, or
- an object where the keys are the local binding name and the value is either:
- the key (string or Symbol) to search for in available injections, or
- an object where:
- the
from
property is the key (string or Symbol) to search for in available injections, and - the
default
property is used as fallback value
- the
Note: the
provide
andinject
bindings are NOT reactive. This is intentional. However, if you pass down a reactive object, properties on that object do remain reactive.Example:
// parent component providing 'foo' const Provider = { provide: { foo: 'bar' } // ... } // child component injecting 'foo' const Child = { inject: ['foo'], created() { console.log(this.foo) // => "bar" } // ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16With ES2015 Symbols, function
provide
and objectinject
:const s = Symbol() const Provider = { provide() { return { [s]: 'foo' } } } const Child = { inject: { s } // ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14Using an injected value as the default for a prop:
const Child = { inject: ['foo'], props: { bar: { default() { return this.foo } } } }
1
2
3
4
5
6
7
8
9
10Using an injected value as data entry:
const Child = { inject: ['foo'], data() { return { bar: this.foo } } }
1
2
3
4
5
6
7
8Injections can be optional with default value:
const Child = { inject: { foo: { default: 'foo' } } }
1
2
3
4
5If it needs to be injected from a property with a different name, use
from
to denote the source property:const Child = { inject: { foo: { from: 'bar', default: 'foo' } } }
1
2
3
4
5
6
7
8Similar to prop defaults, you need to use a factory function for non-primitive values:
const Child = { inject: { foo: { from: 'bar', default: () => [1, 2, 3] } } }
1
2
3
4
5
6
7
8See also: Provide / Inject
# setup
- Type:
Function
The setup
function is a new component option. It serves as the entry point for using the Composition API inside components.
Invocation Timing
setup
is called right after the initial props resolution when a component instance is created. Lifecycle-wise, it is called before the beforeCreate hook.Usage with Templates
If
setup
returns an object, the properties on the object will be merged on to the render context for the component's template:<template> <div>{{ count }} {{ object.foo }}</div> </template> <script> import { ref, reactive } from 'vue' export default { setup() { const count = ref(0) const object = reactive({ foo: 'bar' }) // expose to template return { count, object } } } </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Note that refs returned from
setup
are automatically unwrapped when accessed in the template so there's no need for.value
in templates.Usage with Render Functions / JSX
setup
can also return a render function, which can directly make use of reactive state declared in the same scope:import { h, ref, reactive } from 'vue' export default { setup() { const count = ref(0) const object = reactive({ foo: 'bar' }) return () => h('div', [count.value, object.foo]) } }
1
2
3
4
5
6
7
8
9
10Arguments
The function receives the resolved props as its first argument:
export default { props: { name: String }, setup(props) { console.log(props.name) } }
1
2
3
4
5
6
7
8Note this
props
object is reactive - i.e. it is updated when new props are passed in, and can be observed and reacted upon usingwatchEffect
orwatch
:export default { props: { name: String }, setup(props) { watchEffect(() => { console.log(`name is: ` + props.name) }) } }
1
2
3
4
5
6
7
8
9
10However, do NOT destructure the
props
object, as it will lose reactivity:export default { props: { name: String }, setup({ name }) { watchEffect(() => { console.log(`name is: ` + name) // Will not be reactive! }) } }
1
2
3
4
5
6
7
8
9
10The
props
object is immutable for userland code during development (will emit warning if user code attempts to mutate it).The second argument provides a context object which exposes various objects and functions that might be useful in
setup
:const MyComponent = { setup(props, context) { context.attrs context.slots context.emit context.expose } }
1
2
3
4
5
6
7
8attrs
,slots
, andemit
are equivalent to the instance properties$attrs
,$slots
, and$emit
respectively.attrs
andslots
are proxies to the corresponding values on the internal component instance. This ensures they always expose the latest values even after updates so that we can destructure them without worrying about accessing a stale reference:const MyComponent = { setup(props, { attrs }) { // a function that may get called at a later stage function onClick() { console.log(attrs.foo) // guaranteed to be the latest reference } } }
1
2
3
4
5
6
7
8expose
, added in Vue 3.2, is a function that allows specific properties to be exposed via the public component instance. By default, the public instance retrieved using refs,$parent
, or$root
is equivalent to the internal instance used by the template. Callingexpose
will create a separate public instance with the properties specified:const MyComponent = { setup(props, { expose }) { const count = ref(0) const reset = () => count.value = 0 const increment = () => count.value++ // Only reset will be available externally, e.g. via $refs expose({ reset }) // Internally, the template has access to count and increment return { count, increment } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15There are a number of reasons for placing
props
as a separate first argument instead of including it in the context:It's much more common for a component to use
props
than the other properties, and very often a component uses onlyprops
.Having
props
as a separate argument makes it easier to type it individually without messing up the types of other properties on the context. It also makes it possible to keep a consistent signature acrosssetup
,render
and plain functional components with TSX support.
See also: Composition API