Как мы все знаем, при разработке компонентов самой большой проблемой является взаимодействие между компонентами. В Vue Vue предоставляет множество методов связи компонентов, от базовых props/$emit до EventBus для связи между родственными компонентами и Vuex для глобального управления данными.
Во многих способах взаимодействия компонентов предоставление/внедрение кажется очень акалинским (отсутствие смысла существования). Однако на самом деле обеспечение/инъекция тоже имеет место быть. Сегодня поговорим о применении Provide/Inject во Vue.
Что такое обеспечить / ввести
Provide/inject — это новый API, добавленный Vue в версии 2.2.0.Официальный сайт выглядит следующим образом:
Эту пару опций необходимо использовать вместе, чтобы позволить компоненту-предку внедрить зависимость во все его потомки, независимо от того, насколько глубока иерархия компонентов, и она всегда будет действовать, пока устанавливаются отношения восходящего и нисходящего потоков. Если вы знакомы с React, это похоже на контекстные функции React.
Объяснение на официальном сайте очень запутанное, поэтому я перевожу эти предложения:
обеспечить может указать в компоненте-предке, что мы хотимпоставкаданные или методы для компонентов-потомков, и в любом компоненте-потомке мы можем использовать инъекцию для получения предоставленияпоставкаданные или методы.
Возьмите официальный сайт 🌰:
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
Как видите, переменная foo, предоставленная родительским компонентом, успешно получена и используется дочерним компонентом.
Поняв, что такое «обеспечить/внедрить», давайте снова воспользуемся «предоставлением/внедрением».
Используйте предоставление/внедрение для глобального управления состоянием
В повседневной разработке мы часто используем Vuex для управления состоянием, но лично мне не нравится использовать Vuex, потому что Vuex слишком громоздкий, чтобы использовать его для отслеживания состояния; а проекты, в которых я участвовал раньше, меньше подходят для многозадачности. -человек, эта функция для меня маловажна, мне нужна только функция предоставления глобального состояния в Vuex.
Итак, есть ли удобный и быстрый способ реализовать глобальное состояние? Конечно, это способ использовать черный технологический API для предоставления/внедрения.
Многие люди могут придумать способ: в корневом компоненте передать переменные, а затем использовать их в компонентах-потомках.
// 根组件提供一个非响应式变量给后代组件
export default {
provide () {
return {
text: 'bar'
}
}
}
// 后代组件注入 'app'
<template>
<div>{{this.text}}</div>
</template>
<script>
export default {
inject: ['text'],
created() {
this.text = 'baz' // 在模板中,依然显示 'bar'
}
}
</script>
Эта идея и верна, и неверна из-за специфики обеспечения.
В официальной документации сайта есть такая подсказка о Provide/inject:
намекать:
provide
а такжеinject
Привязки не реактивны. Это сделано намеренно. Однако, если вы передаете прослушиваемый объект, свойства объекта по-прежнему реагируют.
То есть Vue не будет реактивно обрабатывать переменные в provider. Следовательно, для того, чтобы переменные, принимаемые inject, были чувствительными, переменные, предоставленные провайдером, должны быть чувствительными сами по себе.
Поскольку различные состояния внутри компонента реагируют, мы напрямую внедряем сам компонент в предоставление в корневом компоненте.В это время мы можем произвольно обращаться ко всем состояниям в корневом компоненте в компонентах-потомках, и корневой компонент становится глобальное состояние Контейнер, подумайте, очень ли он похож на контекст в React?
код показывает, как показано ниже:
// 根组件提供将自身提供给后代组件
export default {
provide () {
return {
app: this
}
},
data () {
return {
text: 'bar'
}
}
}
// 后代组件注入 'app'
<template>
<div>{{this.app.text}}</div>
</template>
<script>
export default {
inject: ['app'],
created() {
this.app.text = 'baz' // 在模板中,显示 'baz'
}
}
</script>
Некоторые учащиеся могут спросить: корневой узел по-прежнему можно получить с помощью $root, так зачем нам использовать предоставление/внедрение?
В реальной разработке проект часто разрабатывается несколькими людьми, и каждому человеку могут потребоваться разные глобальные переменные.Если все глобальные переменные единообразно определены в корневом компоненте, это неизбежно вызовет такие проблемы, как конфликты переменных.
Использование предоставления/внедрения из входных компонентов разных модулей в соответствующие дочерние компоненты может прекрасно решить эту проблему.
Используйте обеспечение/внедрение с осторожностью
Поскольку Provide/Inject настолько просты в использовании, то почему VUE официально рекомендуется использовать VUEX, а не оригинальный API?
Я упомянул ранее, Vuex и предоставляющую / предоставить / введенную большую разницу, заключается в том, что каждая модификация глобального состояния в Vuex - отслеживать обратно, а модификация переменных в предоставлении / впрыревших не контролируются, другими словами, вы не знаете, какой компонент модифицировал это глобальное состояние.
Концепция дизайна Vue заимствована из принципа одностороннего потока данных в React (хотя есть такой парень, как синхронизация, который разрушает односторонний поток данных), а предоставление/внедрение явно нарушает принцип одностороннего потока данных. Только представьте, если есть несколько компонентов-потомков, которые одновременно зависят от состояния, предоставленного компонентом-предком, тогда, пока один компонент изменяет состояние, все компоненты будут затронуты. С одной стороны, это увеличивает степень связанности, с другой — делает изменения данных неконтролируемыми. В многопользовательской совместной разработке это становится кошмаром.
Здесь я резюмирую два принципа использования Provide/Inject для глобального управления состоянием:
- Когда несколько человек сотрудничают, хорошо поработайте над изоляцией области.
- Попробуйте использовать одноразовые данные в качестве глобального состояния
Кажется, что использование Provide/Inject для управления глобальным состоянием кажется опасным, так что есть ли лучший способ использовать Provide/Inject? Конечно, есть, и это для использования Provide/Inject для написания компонентов.
Написание компонентов с использованием Provide/Inject
Использование Provide/Inject для разработки компонентов — это практика, рекомендованная в официальной документации Vue.
Возьмем в качестве примера знакомый elementUI:
В elementUI есть компонент Button (кнопка).При использовании в компоненте Form (формы) на его размер будет влиять свойство size внешнего компонента FormItem и внешнего компонента Form.
Если это обычное решение, мы можем начать с формы через свойства и передавать значения свойств вниз по одному слою за раз. Похоже, нужно просто пройти два слоя и это приемлемо. Однако компонент следующего уровня Form не обязательно является FormItem, а компонент следующего уровня FormItem не обязательно является Button, и между ними могут быть вложены другие компоненты, то есть иерархическая связь неопределенна. Если используются реквизиты, компоненты, которые мы пишем, будут сильно связаны.
Provide/inject может прекрасно решить эту проблему, нужно только внедрить сам компонент (контекст) в потомка, и компонент-потомок может получить доступ к состоянию в компоненте-предке произвольно, независимо от иерархии.
Часть исходного кода выглядит следующим образом:
// Button 组件核心源码
export default {
name: 'ElButton',
// 通过 inject 获取 elForm 以及 elFormItem 这两个组件
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
// ...
computed: {
_elFormItemSize() {
return (this.elFormItem || {}).elFormItemSize;
},
buttonSize() {
return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
},
//...
},
// ...
};
Суммировать
Фактически, при изучении Vue, следуя правилу двадцати восьми, 20% API, которые мы обычно используем, могут решить большинство повседневных проблем, а остальные API кажутся менее полезными. Тем не менее, найдите время, чтобы узнать об этих непопулярных API, и, возможно, вы сможете найти какой-нибудь необычный пейзаж, который заставит вас делать больше с меньшими затратами при решении некоторых проблем.