Эта статья впервые появилась в моем блоге:«Попробуйте Composition API из Vue 3.0»
Некоторое время назад Vue официально выпустилComposition API RFCдокументацию, и я начал с ней, как только получил новости.
Хотя Vue 3.0 еще не выпущен, его Composition API, который находится на стадии RFC, уже доступен через плагины.@vue/composition-apiопыт. В следующем содержании я создам приложение TODO LIST, чтобы испытать использование Composition API.
Код для этого примера:Github.com/ называется RAIN AU/VU...
Во-первых, Vue 2.x позволяет создавать приложения.
Это приложение TODO LIST очень простое и состоит только из поля ввода, переключателя состояния и списка TODO:
Каждый может такжездесьопыт.
с помощьюvue-cliПосле инициализации проекта наша структура проекта выглядит следующим образом (обсуждается только/srcсодержание):
.
├── App.vue
├── components
│ ├── Inputer.vue
│ ├── Status.vue
│ └── TodoList.vue
└── main.js
от/componentsИмена файлов найти нетрудно, и три компонента соответствуют полю ввода, переключателю состояний и списку TODO приложения TODO LIST. Коды этих трех компонентов очень просты и обсуждаться не будут, здесь обсуждаются только основные.App.vueлогика.
App.vue
<template>
<div class="main">
<Inputer @submit="submit" />
<Status @change="onStatusChanged" />
<TodoList
:list="onShowList"
@toggle="toggleStatus"
@delete="onItemDelete"
/>
</div>
</template>
<script>
import Inputer from './components/Inputer'
import TodoList from './components/TodoList'
import Status from './components/Status'
export default {
components: {
Status,
Inputer,
TodoList
},
data () {
return {
todoList: [],
showingStatus: 'all'
}
},
computed: {
onShowList () {
if (this.showingStatus === 'all') {
return this.todoList
} else if (this.showingStatus === 'completed') {
return this.todoList.filter(({ completed }) => completed)
} else if (this.showingStatus === 'uncompleted') {
return this.todoList.filter(({ completed }) => !completed)
}
}
},
methods: {
submit (content) {
this.todoList.push({
completed: false,
content,
id: parseInt(Math.random(0, 1) * 100000)
})
},
onStatusChanged (status) {
this.showingStatus = status
},
toggleStatus ({ isChecked, id }) {
this.todoList.forEach(item => {
if (item.id === id) {
item.completed = isChecked
}
})
},
onItemDelete (id) {
let index = 0
this.todoList.forEach((item, i) => {
if (item.id === id) {
index = i
}
})
this.todoList.splice(index, 1)
}
}
}
</script>
В приведенной выше логике кода мы используемtodoListМассивы хранят данные списка, используютonShowListПо государственным условиямshowingStatusОтображаются разные списки. существуетmethodsОбъект определяет методы добавления элементов, переключения состояний элементов и удаления элементов. В целом все очень интуитивно понятно и просто.
Согласно официальному заявлению Vue, метод написания 2.x относится к стилю Options-API, а логика объявляется на основе конфигурации. А затем мы рефакторим приведенную выше логику, используя стиль Composition-API.
2. Рефакторинг логики в стиле Composition-API
загружен@vue/composition-apiПосле плагина следуйте документации наmain.jsСсылки открывают возможности Composition API.
main.js
import Vue from 'vue'
import App from './App.vue'
import VueCompositionApi from '@vue/composition-api'
Vue.config.productionTip = false
Vue.use(VueCompositionApi)
new Vue({
render: h => h(App),
}).$mount('#app')
назадApp.vue,от@vue/composition-apiВведение в плагин{ reactive, computed, toRefs }Три функции:
import { reactive, computed, toRefs } from '@vue/composition-api'
оставить толькоcomponents: { ... }варианты, удалите остальные, потом напишитеsetup()функция:
export default {
components: { ... },
setup () {}
}
Далее мы будемsetup()Перепишите предыдущую логику в функции.
Сначала определитеданные.
Чтобы сделать данные «отзывчивыми», нам нужно использоватьreactive()илиref()чтобы обернуть его. Разница между этими двумя функциями будет объяснена в последующих главах. Теперь мы будем использоватьreactive()Приходить.
существуетsetup()В функции определим реактивнуюdataОбъект, аналогичный стилю 2.xdata()элемент конфигурации.
setup () {
const data = reactive({
todoList: [],
showingStatus: 'all',
onShowList: computed(() => {
if (data.showingStatus === 'all') {
return data.todoList
} else if (data.showingStatus === 'completed') {
return data.todoList.filter(({ completed }) => completed)
} else if (data.showingStatus === 'uncompleted') {
return data.todoList.filter(({ completed }) => !completed)
}
})
})
}
где вычисляемые свойстваonShowListпрошедшийcomputed()Обертка функции, чтобы она могла изменяться в зависимости от изменений данных, от которых она зависит.
Следующее определениеметод.
существуетsetup()В функции методы предыдущих вариантов операции можно использовать сразу после небольшой модификации:
function submit (content) {
data.todoList.push({
completed: false,
content,
id: parseInt(Math.random(0, 1) * 100000)
})
}
function onStatusChanged (status) {
data.showingStatus = status
}
function toggleStatus ({ isChecked, id }) {
data.todoList.forEach(item => {
if (item.id === id) {
item.completed = isChecked
}
})
}
function onItemDelete (id) {
let index = 0
data.todoList.forEach((item, i) => {
if (item.id === id) {
index = i
}
})
data.todoList.splice(index, 1)
}
в пределахmethods: {}Форма, определенная в объекте, отличается тем, чтоsetup()Метод не может пройтиthisдля доступа к данным в экземпляре, но путем прямого чтенияdataпосетить.
Наконец, просто верните только что определенные данные и методы:
return {
...toRefs(data),
submit,
onStatusChanged,
toggleStatus,
onItemDelete,
}
используется здесьtoRefs()ДатьdataОбъект упакован, чтобы его данные оставались «отзывчивыми», а исходный комитет будет расширен в последующих главах.
После завершения рефакторинга обнаруживается, что результаты его работы точно такие же, как и предыдущие, что доказывает, что Composition API может работать корректно. Далее поговоримreactive()а такжеref()Эта проблема.
3. Реагирующие данные
Мы знаем, что одним из преимуществ Vue является его мощная адаптивная система. Независимо от версии, эта основная функциональность присутствует повсюду. И говоря оОтзывчивая система, часто неотделимый ототзывчивые данные, что также является темой, о которой говорят все.
Напомним, что в версии 2.x Vue использовалObject.defineProperty()Этот метод переписывает объект и встраивает логику, связанную с отзывчивой системой, в его геттер и сеттер, чтобы при изменении объекта можно было активировать соответствующую логику. В следующей версии 3.0 Vue будет использоватьProxyчтобы завершить функцию здесь. Чтобы испытать так называемые «реактивные объекты», мы можем напрямую передать API, предоставляемый Vue.Vue.observable()реализовать:
const state = Vue.observable({ count: 0 })
const Demo = {
render(h) {
return h('button', {
on: { click: () => { state.count++ }}
}, `count is: ${state.count}`)
}
}
Приведенный выше код взят изофициальная документация
Как видно из кода, поVue.observable()упакованныйstate, уже имеет адаптивные функции, при нажатии на кнопкуcountЗначение изменится, и это изменение приведет к обновлению слоя представления.
Возвращаясь к Composition API, егоreactive()а такжеref()Функция также заключается в достижении аналогичной функции, и@vue/composition-apiТакже из основной вилкиVue.observable():
function observe<T>(obj: T): T {
const Vue = getCurrentVue();
let observed: T;
if (Vue.observable) {
observed = Vue.observable(obj);
} else {
const vm = createComponentInstance(Vue, {
data: {
?state: obj,
},
});
observed = vm._data.?state;
}
return observed;
}
выдержка изИсходный код плагина
в пониманииreactive()а такжеref()После цели мы можем проанализировать разницу между ними.
Сначала давайте посмотрим на два фрагмента кода:
// style 1: separate variables
let x = 0
let y = 0
function updatePosition(e) {
x = e.pageX
y = e.pageY
}
// --- compared to ---
// style 2: single object
const pos = {
x: 0,
y: 0
}
function updatePosition(e) {
pos.x = e.pageX
pos.y = e.pageY
}
Предположениеxа такжеyвсе данные, которые должны иметь «отзывчивые» возможности, тоref()Он эквивалентен первому стилю, предоставляя возможности реагирования только на часть данных; иreactive()Это эквивалентно второму стилю, дающему возможность реагировать на весь объект.
Но в конкретном использовании, черезreactive()Обернутый объект будет иметь яму. Если вы хотите сохранить отзывчивость содержимого объекта, вы должны вернуть весьreactive()Объект возвращается, и при обращении необходимо ссылаться на весь объект, в противном случае способность ответа этого содержимого объекта будет потеряна. Это немного примерно, можете посмотреть на примере официального сайта для углубления понимания:
// composition function
function useMousePosition() {
const pos = reactive({
x: 0,
y: 0
})
// ...
return pos
}
// consuming component
export default {
setup() {
// reactivity lost!
const { x, y } = useMousePosition()
return {
x,
y
}
// reactivity lost!
return {
...useMousePosition()
}
// this is the only way to retain reactivity.
// you must return `pos` as-is and reference x and y as `pos.x` and `pos.y`
// in the template.
return {
pos: useMousePosition()
}
}
}
дать одиннеприличныйпример. «Объектные признаки» даны всему «предмету», если содержание в нем хочет иметь и эту часть признаков, то она может быть только связана с предметом, а не может быть выделена отдельно.
Однако в конкретном бизнесе, если деструктурирование не может быть использовано для извлеченияreactive()Значение объекта, которое нужно передавать каждый раз.Операторам будет очень хлопотно получить доступ к свойствам в нем, поэтому чиновник предоставляетtoRefs()функция, чтобы заполнить эту дыру для нас. просто используйтеtoRefs()Пучокreactive()После того, как объект упакован, содержимое в нем можно использовать независимо посредством деструктуризации, и в это время содержимое все еще сохраняет адаптивные характеристики.
Что касается того, когда использоватьreactive()а такжеref(), выбираются в соответствии с определенной бизнес-логикой. Лично я предпочел бы использоватьreactive()соответствоватьtoRefs()использовать, потому что послеref()Инкапсулированные данные должны пройти.valueЧтобы получить доступ к значению внутри, есть относительно больше мест, на которые следует обратить внимание в письменной форме.
В-четвертых, преимущества и расширения Composition API.
Одной из серьезных проблем Vue является повторное использование логики. По мере усложнения проекта все больше и больше логики можно абстрагировать и использовать повторно. Но Vue можно решить только миксинами на стадии 2.x (конечно, HOC также можно реализовать очень округло, что здесь не будет расширяться). Миксины просто сливают логику кода.Если вам нужно отслеживать логику, это будет очень болезненный процесс, потому что часто бывает трудно сразу увидеть, какие данные или методы взяты из миксинов, а какие из сложной бизнес-логики. текущий компонент.
Еще один момент — поддержка TypsScript. Чтобы лучше выполнять вывод типов, хотя в 2.x также есть реализация ts в стиле класса, его многословный и нестабильный декоратор не является хорошим решением. Вдохновленный React Hooks, Vue Composition API завершает логику в форме композиции функций, которая, естественно, подходит для использования с TypeScript.
Что касается вопроса о том, что лучше между Options API и Composition API, то в примере, показанном в этой статье, на самом делетрудно отличитьДа, причина в том, что логика этого примера слишком проста. Но если подумать, то нетрудно обнаружить, что если проект достаточно сложный, то Composition API может очень хорошо извлечь логику.setup()Значение, возвращаемое функцией, можно легко отследить (например, в VSCode нажмите cmd и щелкните имя переменной, чтобы перейти к ее определению). Такие возможности могут быть очень полезны при сопровождении крупномасштабных проектов или совместных проектов с участием нескольких человек, а общая логика также может использоваться более детально.
С концепцией дизайна и преимуществами Composition API можно ознакомиться на официальном сайте.Глава мотивации.
Если дыра в мозгу больше, Composition API может иметь более крутой игровой процесс.
-
Для некоторых сторонних библиотек компонентов (таких как element-ui), помимо предоставления компонентов, содержащих стиль, структуру и логику, некоторая логика также может быть предоставлена в виде Composition API, и его возможности настройки и игровой процесс будут более богатыми.
-
reactive()методы могут сделать объект реактивным, сwatch()Методы легко справляются с побочными эффектами:import { reactive, watch } from 'vue' const state = reactive({ count: 0 }) watch(() => { document.body.innerHTML = `count is ${state.count}` })В приведенном выше примере, когда отзывчивый
state.countПосле изменения он сработаетwatch()обратный вызов внутри функции. Исходя из этого, возможно, мы сможем использовать эту функцию для решенияДругие платформыпросмотреть проблему с обновлением. Среда разработки апплетов WeChat mpvue реализует привязку данных и обновление представлений апплета путем изменения исходного кода Vue.Если у нас есть Composition API, возможно, мы сможем передатьreactive()а такжеwatch()и другие методы для достижения аналогичных функций, в это время Vue будет расположен вданныеа такжеПосмотретьВ среднем слое привязка данных размещается вreactive(), а обновление представления равномерно размещается вwatch()осуществляется посередине.
V. Резюме
С помощью приложения TODO LIST эта статья завершила раннее изучение Composition API в соответствии с рекомендациями официального веб-сайта, изучила использование нового API, обсудила некоторые концепции дизайна, проанализировала некоторые проблемы и, наконец, открыла противоположное использование было изучено. Из-за отсутствия соответствующей информации и Composition API все еще находится на стадии RFC, в статье могут быть неизбежные ошибки.Если у вас есть какие-либо мнения и взгляды, пожалуйста, не стесняйтесь общаться со мной.