기존에는 부모에서 자식 컴포넌트로 데이타를 전달해야할 경우엔 props
를 사용하였다. 만약, 컴포넌트 구조가 복잡하게 중첩되어있을 경우엔, drilling으로 데이타를 전달해야 하며, 이 작업은 매우 짜증난다…
이러한 문제를 해결하기 위해 provide
, inject
를 사용한다. 부모 컴포넌트가 provider가 되어 그 하위의 모든 자식들에게 데이타를 전달하게 된다. 부모는 provide
option으로 데이타를 전달하게 되고, 자식 컴포넌트는 inject
option으로 데이타를 사용하게 된다.
(리액트의 Context API가 이러한 역할을 한다. Context.Provider / Context.Consumer가 provide/inject에 대응한다.)
부모 컴포넌트 쪽에서 provide로 데이터를 넘긴다. 이 때, provide는 객체를 넘기는 함수인데, 이렇게 해야 component instance property를 자식 컴포넌트에게 넘길 수 있다.
app.component('todo-list', {
data() {
return {
todos: ['Feed a cat', 'Buy tickets']
}
},
provide() {
return {
todoLength: this.todos.length
}
},
template: `
...
`
})
app.component('todo-list-statistics', {
inject: ['todoLength'],
created() {
console.log(`Injected property: ${this.todoLength}`) // > Injected property: John Doe
}
})
만약, component instance property가 아닌 값을 넘겨줄 때는 provide는 다음과 같은 형태여도 된다.
provide: {
location: "North Pole",
geolocation: {
longitude: 90,
latitude: 135,
},
},
기본적으로 provide/inject는 reactive하지 않다. 따라서, todos 배열의 길이가 달라져도, 주입된 todoLength property에는 반영되지 않는다.
반응형을 추가하고 싶으면
여기서는 Composition API의 computed
프로퍼티를 todoLength에 추가하였다.
injected property를 가져올 때는 this.todoLength.value로 가져온 것을 알 수 있다.
app.component('todo-list', {
// ...
provide() {
return {
todoLength: Vue.computed(() => this.todos.length)
}
}
})
app.component('todo-list-statistics', {
inject: ['todoLength'],
created() {
console.log(`Injected property: ${this.todoLength.value}`) // > Injected property: 5
}
})
Composition API에서 provide, inject를 사용할 수 있다.
setup()안에서 provide를 사용하기 위해서는 vue에서 provide를 import해야 한다.
provide 함수로는 두 값을 전해주어야 한다.
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
provide('location', 'North Pole')
provide('geolocation', {
longitude: 90,
latitude: 135
})
}
}
</script>
setup()안에서 inject 사용하려면 vue에서 import 해와야 한다.
inject함수는 두 파라미터를 받는다.
<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
return {
userLocation,
userGeolocation
}
}
}
</script>
반응형을 추가하기 위해선 ref
나 reactive
를 provide할 value에 추가해야 한다.
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
provide('location', location)
provide('geolocation', geolocation)
}
}
</script>
reactive property를 변경하는 것은 provider 안에서 하는 것을 추천한다.
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
provide('location', location)
provide('geolocation', geolocation)
return {
location
}
},
methods: {
updateLocation() { // provider안에서 location property 변경하는 메소드 추가
this.location = 'South Pole'
}
}
}
</script>
만약, 데이타를 inject받은 컴포넌트에서 데이타를 변경해야 할 경우도 있을 것이다. 이럴 때는, reactive property를 변경할 메소드를 provider쪽에서 전달할 것을 추천한다.
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import { provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', location)
provide('geolocation', geolocation)
provide('updateLocation', updateLocation)
}
}
</script>
readonly
사용하여 상수화하기값이 변경되어서는 안될 프로퍼티에는 readonly
를 provider 쪽에서 추가하여, injected component 쪽에서 값을 변경시키지 못하도록 할 것을 추천한다.
<script>
import { provide, reactive, readonly, ref } from 'vue'
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
setup() {
const location = ref('North Pole')
const geolocation = reactive({
longitude: 90,
latitude: 135
})
const updateLocation = () => {
location.value = 'South Pole'
}
provide('location', readonly(location))
provide('geolocation', readonly(geolocation))
provide('updateLocation', updateLocation)
}
}
</script>
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Do you want to remove this version name and description?
Syncing