Vue 3 composition API and access to Vue instance Vue 3 composition API and access to Vue instance vue.js vue.js

Vue 3 composition API and access to Vue instance


Use provide/inject

Provide

const app = createApp(App);app.provide('someVarName', someVar);  // `Provide` a variable to all components here

Inject:

// In *any* componentconst { inject } = Vue;...setup() {  const someVar = inject('someVarName');   // injecting variable in setup}

Note that you don't have to provide from the app root, but can also provide from any component to only its sub-components:

// In *any* componentsetup() {  ...},provide() {  return {    someVarName: someVar  }}

Original answer

[Edit: While my original answer below is still useful for context properties, it's no longer recommended to use context.root, which is no longer mentioned in the guide and may soon be deprecated.]

In Vue 3, setup has an optional second argument for context. You can access the Vue instance through context.root instead of this:

setup(props, context) {  context.root.$myUtilFunc  // same as `this.$myUtilFunc` in Vue 2}

Things you can access through context:

context.attrscontext.slotscontext.parentcontext.rootcontext.emit


While Dan's answer is correct, I would like to provide an alternative mentioned in the comments to the accepted answer. There are pros and cons to each, so, you need to choose based on your needs.

To understand why the code below works, it is important to remember, that provided properties are transitive in the tree of components. I.e. inject('foo') will look for 'foo' in every parent going up the hierarchy all the way to the app; there is no need to declare anything in the middle wrappers.

So, we can write something like this, where globalDateFormatter() is just an example function we want to use in any component down the tree:

main.js

import { createApp } from 'vue'import App from './App.vue'const globalDateFormatter = (date) => {    return '[' + date.toLocaleString() + ']'}const app = createApp(App)app.provide('globalDateFormatter', globalDateFormatter) // <-- define hereapp.mount('#app')

And then, in some DeepDownComponent.vue:

<template>  <p> {{ fmt(new Date()) }} </p></template><script>import { inject } from 'vue'export default {    setup(){        const fmt = inject('globalDateFormatter', x => x.toString())         //           ^-- use here, optional 2nd parameter is the default        return {fmt}    }}</script>

Obviously, you can directly import and use provide and inject with the following signatures

provide<T>(key: InjectionKey<T> | string, value: T): void

and

inject<T>(key: InjectionKey<T> | string, defaultValue: T): T

anywhere in your code, doesn't have to be app.provide()

You can also provide values, even the global store, like this, just don't forget to use ref() or reactive() as needed.

In short, whenever you would prefer dependency injection, provide/inject are your friends.