# 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: 'Северный полюс',
    geolocation: {
      longitude: 90,
      latitude: 135
    }
  }
}
</script>
1
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>
1
2
3
4
5
6

# Использование Provide

Для использования provide в setup() потребуется сначала явно импортировать метод из vue. Это позволяет определить каждое свойство своим собственным вызовом provide.

Функция provide позволяет определить свойство с помощью двух аргументов:

  1. Имя свойства (тип <String>)
  2. Значение свойства

Внедряемые значения в компоненте 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', 'Северный полюс')
    provide('geolocation', {
      longitude: 90,
      latitude: 135
    })
  }
}
</script>
1
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 принимает два аргумента:

  1. Имя внедряемого свойства
  2. Значение по умолчанию (опционально)

Код в компоненте MyMarker можно переписать следующим образом:



 


 
 
 
 
 
 
 
 
 



<!-- src/components/MyMarker.vue -->
<script>
import { inject } from 'vue'

export default {
  setup() {
    const userLocation = inject('location', 'Вселенная')
    const userGeolocation = inject('geolocation')

    return {
      userLocation,
      userGeolocation
    }
  }
}
</script>
1
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('Северный полюс')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })

    provide('location', location)
    provide('geolocation', geolocation)
  }
}
</script>
1
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 рекомендуется сохранять любые мутации реактивных свойств внутри провайдера во всех случаях, когда это возможно.

Например, если потребуется изменять местоположение пользователя, то лучшим способом будет это делать внутри компонента 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('Северный полюс')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })

    provide('location', location)
    provide('geolocation', geolocation)

    return {
      location
    }
  },
  methods: {
    updateLocation() {
      this.location = 'Южный полюс'
    }
  }
}
</script>
1
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('Северный полюс')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })

    const updateLocation = () => {
      location.value = 'Южный полюс'
    }

    provide('location', location)
    provide('geolocation', geolocation)
    provide('updateLocation', updateLocation)
  }
}
</script>
1
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', 'Вселенная')
    const userGeolocation = inject('geolocation')
    const updateUserLocation = inject('updateLocation')

    return {
      userLocation,
      userGeolocation,
      updateUserLocation
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Также рекомендуется использовать readonly на предоставляемых свойствах, если нужно гарантировать, чтобы передаваемые через provide данные не изменялись компонентом, в который внедряются.







 

















 
 





<!-- 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('Северный полюс')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })

    const updateLocation = () => {
      location.value = 'Южный полюс'
    }

    provide('location', readonly(location))
    provide('geolocation', readonly(geolocation))
    provide('updateLocation', updateLocation)
  }
}
</script>
1
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