# Provide / Inject
このページは、すでに Provide / Inject、Composition API 導入、リアクティブの基礎を読み終えていることを想定しています。
provide / inject は Composition API でも使うことができます。どちらも現在アクティブなインスタンスの setup()
中にのみ呼び出すことが可能です。
# シナリオの背景
これから、Composition API を使用して、以下のコードを書き直そうとしているとしましょう。以下のコードでは、MyMap
コンポーネントが MyMarker
コンポーネントにユーザの位置情報を提供しています。
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<script>
import MyMarker from './MyMarker.vue'
export default {
components: {
MyMarker
},
provide: {
location: 'North Pole',
geolocation: {
longitude: 90,
latitude: 135
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- src/components/MyMarker.vue -->
<script>
export default {
inject: ['location', 'geolocation']
}
</script>
2
3
4
5
6
# Provide の使い方
provide
を setup()
内で使う場合、始めに vue
から明示的に provide
をインポートします。これにより、 各プロパティについて provide
の呼び出しで定義することができるようになります。
provide
関数は2つの引数によってプロパティを定義できます:
- プロパティの名前 (
<String>
型) - プロパティの値
MyMap
コンポーネントは、以下のようにリファクタリングすることができます:
<!-- 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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Inject の使い方
inject
を setup()
内で使う場合も、vue
から明示的に inject
をインポートする必要があります。そうしておけば、これを呼び出すことで、注入された値をコンポーネントに公開する方法を定義することができるようになります。
inject
関数は2つの引数をとります:
- 注入されるプロパティ名
- デフォルト値 (任意)
MyMarker
コンポーネントは、以下のようにリファクタリングすることができます:
<!-- 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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# リアクティブ
# リアクティブの追加
提供された値と注入された値をリアクティブにするには、値を提供する際に ref または reactive を使います。
MyMap
コンポーネントは、以下のように変更できます:
<!-- 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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
これで、どちらかのプロパティに何か変更があった場合、MyMarker
コンポーネントも自動的に更新されるようになります。
# リアクティブプロパティの変更
リアクティブな provide / inject の値を使う場合、リアクティブなプロパティに対しての変更は可能な限り 提供する側 の内部に留めることが推奨されます
例えば、以下の location を変更する必要があるイベントでは、location の変更は MyMap
コンポーネント内で行われるのが理想的です。
<!-- 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)
return {
location
}
},
methods: {
updateLocation() {
this.location = 'South Pole'
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
しかし、データが注入されたコンポーネント側でデータを更新する必要がある場合もあります。そのような場合、リアクティブなプロパティを更新する責務を持つメソッドを提供することを推奨します。
<!-- 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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'
export default {
setup() {
const userLocation = inject('location', 'The Universe')
const userGeolocation = inject('geolocation')
const updateUserLocation = inject('updateLocation')
return {
userLocation,
userGeolocation,
updateUserLocation
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
最後に、provide
で渡したデータが、注入されたコンポーネント内で変更されないようにしたい場合は、提供するプロパティに readonly
をつけることを推奨します。
<!-- src/components/MyMap.vue -->
<template>
<MyMarker />
</template>
<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>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
← ライフサイクルフック テンプレート参照 →