Provide and Inject
in Vue 3
(and why you might not need vuex)
Who Am I?
- Alex Riviere
- Senior Frontend Developer at Traina
- Co-Organizer for Atlanta Vue.js Meetup
- Co-Host of the Enjoy the Vue Podcast
WARNING
Advanced Vue.js Concepts Ahead
May Cause:
- Confusion
- Sense of Wonder
- Smug satisfaction of knowing more than others.
Methods of Passing State Between Components
- Props/Emit
- External Store (Vuex)
- $root/$parent (Not Advised)
- Provide/Inject
Props Down, Events Up
<parent-component>
<child-component>
<grand-child-component />
$props
$props
$emit
$emit
</child-component>
</parent-component>
Props Down, Events Up
- Explicitly Defined Props and Events
- Creates reusable components
- Doesn't rely on outside data structures
- Easily testable
Pros:
Challenging when your app gets larger, and you need data in a deeply nested component.
Cons:
Global Store
<fox-component />
<whale-component />
<unicorn-component />
Vuex $store
state
state
state
mutation
mutation
mutation
Global Store
- Useful for large applications with shared state
- Can be used along with props/$emit
- Implicitly uses $store
- Relies on external dependency
- Not ideal for publishing modules
Pros:
Cons:
I am $root
<walking-tree-component>
<raccoon-component>
<laser-pew-pew-component />
$root.bitOfData
</raccoon-component>
</walking-tree-component>
I am $root?
<walking-tree-component>
<raccoon-component>
<laser-pew-pew-component />
$root.bitOfData?
</raccoon-component>
</walking-tree-component>
<galaxy-guardians>
</galaxy-guardians>
$parent Knows Best
<parent-component>
<child-component>
<grand-child-component />
$parent.knowledge
$parent.$parent.knowledge
(Has a bit of data called knowledge)
</child-component>
</parent-component>
$parent Knows Best ?
<parent-component>
<grand-child-component />
$parent.$parent.knowledge?
</parent-component>
Provide/Inject
<parent-component>
<grand-child-component />
provide
inject
<child-component>
<grand-parent-component>
</child-component>
</parent-component>
</grand-parent-component>
Provide/Inject
<providing-component>
<injecting-component />
<child-component>
<child-component>
<root-component>
provides.bit_of_data
inject:['bit_of_data']
provides.bit_of_data
provides.bit_of_data
this.bit_of_data
</child-component>
</child-component>
</providing-component>
</root-component>
Provide/Inject
- Can be used to pass data between a
component and its descendants - Doesn't rely on a $root component
containing the right data - Doesn't rely on the correct structure
to find $parent
SHOW ME
HOW ALREADY!
ReactiveProvide.vue
import {ref, provide} from 'vue';
export default {
setup(){
const text = ref('Hello World');
provide('text', text);
return {text}
},
}
Vue 2 + 3
Vue 3 Composition API
export default {
data() {
return {
text: "Hello World",
}
},
provide() {
return {
getText: ()=>this.text,
setText: v=>this.text=v,
}
},
}
ReactiveInject.vue
import {inject} from 'vue'
export default {
name:"reactive-inject",
setup(){
const text = inject('text');
return {text};
},
}
Vue 2 + 3
Vue 3 Composition API
export default {
name:"reactive-inject",
inject: [
"getText",
"setText",
],
computed: {
text: {
get() {
return this.getText()
},
set(d) {
this.setText(d)
},
}
},
}
Reactive Provide/Inject
Where should I use this?
A good example is compound components where the children components only function inside of their parent components.
When data is implicitly expected to be available.
Where should I use this?
Another good example is using it for a
Global or Local Store
When data is implicitly expected to be available.
Where should I use this?
Let's look at an example using an accordion and splitting it up into compound components.
The following example was blatantly stolen from
Cassidy Williams' React Hooks Workshop
Follow Cassidy, because she is awesome:
twitter: cassidoo
An Accordion
- [data-accordion]
- [data-panel-section]
- [data-panel-title]
- [data-panel-content]
Let's break this down
AccordionWrapper
AccordionSection
AccordionTitle
AccordionContent
Bring it Home - All Together
What Else?
🔥You may not need Vuex🔥
- Use Provide and wrap your app, views,
or local components in a Data Layer - Will only load data when you need it
- Might solve your issue with having a giant vuex store load on every page
The
Mildly Over-engineered
Counter
Component
Introducing:
The Counter Component
Our "CounterProvide" Data Layer Component
Our "CounterDisplay" Component
Our "CounterButtons" Update Component
The Fully Realized Counter Component
What have we learned?
- There are many ways of passing data between components
- Props/Emit
- Global Store (Vuex)
- $root/$parent
- Provide/Inject
- Provide/Inject can be used to implicitly pass data between nested components.
- Provide/Inject is fantastic for Compound Components
- You can make your own Data Layers to provide data to your App, Route, or local components!
Questions?
Provide and Inject in Vue 3 - Vue Conf Toronto 2021
By Alex Riviere
Provide and Inject in Vue 3 - Vue Conf Toronto 2021
- 883