Часть 0 — Введение API композиции

в DANA мы постоянно улучшаем качество кода и производительность приложений. Нам важно это сделать. И хорошая новость заключается в том, что в Vue 3 есть функция Composition API, которая направлена ​​на преодоление ограничений и недостатков Options API. Мы узнаем больше о Vue 3 Composition API, чтобы нам было легче понять Composition API, я создал проект приложения Todo, и вы можете напрямую увидеть мой код на GitHub в этом репозитории . Вы также можете получить доступ к демоверсии приложения Todo, созданной по этой ссылке. В Composition API мы изучим Ref, Reactive, toRefs, Methods, Computed Getter & Setter, WatchEffect, Watch , Жизненный цикл, Компонент (Props & Emit).

Composition API в Vue 3 является необязательным, на момент написания этой статьи программисты все еще могли использовать Options API в Vue 3 для разработки веб-приложений. Composition API был создан для преодоления ограничений Option API. Composition API кажется полезным в больших и сложных приложениях. Это связано с тем, что концепция Composition API состоит в том, чтобы разделить несколько логических задач и даже сделать логику многократно используемой. Пример:

setup () {
   const { todos } = useListTodo()
   const { addTodo} = useCrudTodo()
   return {
      todos,
      addTodo
   }
   
   function useListTodo () {
      const todos = ref('')
      return {
         todos
      }
   }
   function useCrudTodo () {
      const addTodo = (e) => {
         console.log(e)
      }
    
      return {
         addTodo
      }
   }
}

Приведенный выше код является примером разделения логических задач, а для того, чтобы сделать функцию многократно используемой, предположим, что мы хотим создать функцию для хранения данных в LocalStorage.

export default function saveDataToLocalStorage(listTodo) {
    localStorage.setItem('todos', JSON.stringify(listTodo))
}

мы сохраняем код в файлеsave-local-storage.js , затем мы можем использовать эту функцию для всех компонентов, пример выглядит следующим образом:

//import file save-local-storage.js
import saveToLocalStorage from '../components/save-local-storage.js'
const addTodo = () => {
   if(!todo.value) return 
   todos.list.unshift({
      activity: todo.value,
      isDone: false
   })
   todo.value = ''
   saveToLocalStorage(todos.list)
}

Установить Вайт

Vite был создан непосредственно создателем Vue.js, а именно Эваном Ю. Миссия Vite — ускорить процесс разработки. Если мы используем Vue CLI, проблема заключается в том, что нам нужно ждать, пока все приложения в Vue завершат сборку, поэтому это будет пустой тратой времени на разработку, особенно если приложение довольно сложное и большое. В отличие от Vue CLI, Vite будет компилировать только те файлы, которые необходимы, а именно файлы, которые изменились. Это ускорит процесс разработки.

На момент написания этой статьи нам нужно было установить узел локально с версией ›=12.0.0. И тогда мы можем установить Vite с помощью npm или yarn.

# npm 6.x
npm init vite@latest my-vue-app --template vue
# npm 7+, extra double-dash is needed:
npm init vite@latest my-vue-app -- --template vue
# yarn
yarn create vite my-vue-app --template vue
# pnpm
pnpm create vite my-vue-app -- --template vue

Установите и настройте Tailwind CSS на Vite

Если мы используем nom для установки Tailwind CSS, то перейдите в каталог проекта и выполните следующую команду в терминале

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

приведенная выше команда создаст файлы filetailwind.config.js и postcss.config.js. затем в файлеtailwind.config.js отредактируйте и настройте следующим образом:

создайте файлindex.css в каталогеsrc и добавьте директиву@tailwind для каждого слоя попутного ветра.

@tailwind base; 
@tailwind components; 
@tailwind utilities;

Последний файл импорта ./src/index.css в файле./src/main.js

мы можем запустить Vite для разработки и использовать Tailwind CSS с командойnpm run dev. Что касается производства, мы используем командуnpm run build. Команда сгенерирует все необходимые ресурсы и сохранит их в каталогеdist.

Часть 1 — Ref, Reactive и toRefs

Ref, Reactive и toRefs — важные части, которые мы должны знать в Composition API. Мы узнаем больше о функциях и примерах их использования.

Настраивать

Composition API использует основную функцию namedsetup , функцияsetup содержит всю нашу логику.

export default {
  setup(props, context) {
    // Attributes (Non-reactive object, equivalent to $attrs)
    console.log(context.attrs)
    // Slots (Non-reactive object, equivalent to $slots)
    console.log(context.slots)
    // Emit events (Function, equivalent to $emit)
    console.log(context.emit)
    // Expose public properties (Function)
    console.log(context.expose)
  }
}

функцияsetup имеет два аргумента, а именно props dan context . props внутри функции setup являются реактивными и будут обновляться при передаче новых реквизитов. Хотя contextаргумент является обычным объектом, а не реактивным,используя ES6, мы можем деструктурирование context следующим образом:

export default {
  setup(props, { attrs, slots, emit, expose }) {
    ...
  }
}

Имейте в виду, что в Composition API мы не определяем data, methods и computed, все они будут заменены концептуальной функцией.

Ссылка

Ref используется для создания реактивных и изменяемых переменных. Ссылка может использоваться только для примитивных данных, таких как логические, строковые и целые числа. Объект Ref имеет одно свойство .value для установки и получения объекта Ref.

import { ref } from 'vue'
export default {
   setup(){
      const todo = ref('todo is empty')
      console.log(todo.value) // todo is empty
        
      todo.value = 'I want to finish Vue course'
      console.log(todo.value)//I want to finish Vue course
      
      return {
         todo
      }
   }
}

Чтобы получить доступ к Ref в HTML-шаблоне, выполните следующие действия:

<input v-model="todo" placeholder="Add anything..." type="text" name="todo"/>
{{ todo }}

реактивный

В отличие от Ref, который можно использовать только для примитивных данных, Reactive можно использовать для объектов. В качестве примера:

import { reactive } from 'vue'
export default {
   setup(){
     const todos = reactive({
       activity: "I want to finish Vue Course",
       isDone: false
     })
     setTimeout( () => {
       todos.activity = "I want to finish Reactjs Course",
       todos.isDone = false
     }, 2000)
     return {
       todos
     }
   }
}

если мы используем Ref, данные в приведенном выше коде не будут реактивными. Поэтому мы можем использовать Reactive. Между тем, чтобы получить доступ к Reactive в HTML-шаблоне, нужно:

{{ todos.activity }} - {{ todos.isDone }}

toRefs

toRefs используется для преобразования реактивного объекта в простой объект. Чтобы лучше понять toRefs, мы приводим пример из практики. Допустим, мы хотим получить доступ к Reactive в HTML-шаблоне следующим образом:

{{ activity }} - {{ isDone }}

В то время как в Composition API код такой:

import { reactive } from 'vue'
export default {
   setup(){
     const todos = reactive({
       activity: "I want to finish Vue Course",
       isDone: false
     })
     setTimeout( () => {
       todos.activity = "I want to finish Reactjs Course",
       todos.isDone = false
     }, 2000)
     return {
       ...todos
     }
   }
}

Используя только синтаксис распространения javascript без использования toRefs, мы потеряем его реактивность. Таким образом, данные не изменятся, даже если мы изменим данные через 2 секунды. Для решения этого случая мы используем toRefs.

import { reactive, toRefs } from 'vue'
export default {
   setup(){
     const todos = reactive({
       activity: "I want to finish Vue Course",
       isDone: false
     })
     setTimeout( () => {
       todos.activity = "I want to finish Reactjs Course",
       todos.isDone = false
     }, 2000)
     return {
       ...toRefs(todos)
     }
   }
}

toRef

В отличие от toRefs, который используется для Reactive, toRef используется для преобразования одного свойства реактивного объекта в Ref. Вот разница

на ссылку

const state = reactive({
  foo: 1,
  bar: 2
})
const fooRef = toRef(state, 'foo')
/*
fooRef: Ref<number>,
*/

ссылки

const state = reactive({
  foo: 1,
  bar: 2
})
const stateAsRefs = toRefs(state)
/*
{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

Часть 2. Методы, вычисляемый геттер и сеттер

Методы

В отличие от Option API, мы должны объявлять функцию внутри методов, в Composition API этого делать не нужно, видите разницу.

data() {
    return { 
       count: 4 
    }
},
methods: {
    increment() {
      // `this` will refer to the component instance
      this.count++
    }
}

При использовании Composition API будет короче.

setup(){
   const count = ref(0)
   const increment = () => {
      count.value++
   }
   return {
      count,
      increment
   }
}

Вычисляемый геттер и сеттер

Чтобы использовать Computed, мы должны вызвать в Vue. Напримерimport { computed } from ‘vue’ Пример использования вычисляемого метода получения и установки см. в приведенном ниже коде.

import { ref, computed } from 'vue'
export default {
   setup(){
     const count = ref(1)
     const result = computed({
       get: () => count.value + 10,
       set: val => {
         console.log('val',val) //0
         count.value = val - 5
       }
     })
     
     result.value = 0
     console.log("count", count.value) //-5
     console.log("result", result.value) //5
     return {
        count,
        result
     }
   }
}

Вызвать Computed в HTML-шаблоне очень просто:

<template>
{{ count }} = {{ result }}
</template>

Но если вы не хотите использовать вычисляемый геттер и сеттер, вот пример:

import { ref, computed } from 'vue'
export default {
   setup(){
      const count = ref(1)
      const result = computed(() => {
         return count.value+10
      })
      result.value = 0
      console.log("count", count.value) // 1
      console.log("result", result.value) // 11
   
      return {
         count,
         result
      }
   }
}

Часть 3 — Смотрите и смотритеЭффект

смотреть

watch полезен для отслеживания изменений в состоянии, мы можем что-то сделать с состоянием, если есть изменение. inwatch мы также можем получить старое значение или предыдущее значение.

Чтобы использовать watch и watchEffect, мы сначала импортируем:

import { watchEffect, watch } from 'vue'

пример использования watch

watch(todo, (newValue, prevValue) => {
   console.log("todo", todo.value)
   console.log("prev", prevValue)
})

Например, чтобы отслеживать изменения состояния более чем в одном:

watch([todo, todos], (newValue, prevValue) => {
   console.log("todo", todo.value)
   console.log("todos", todos)
   console.log("new value", newValue)
   console.log("prev value", prevValue)
})

смотретьЭффект

watchEffect имеет ту же функцию, а именно мониторинг изменений состояния. Разница в том, что watchEffect подходит для мониторинга более чем одного состояния. что следует отметить, watchEffect не может получить доступ к старым значениям или предыдущим значениям в состоянии.

watchEffect( () => {
   console.log("todo", todo.value)
   console.log("todo list", todos.list)
})

особенно для отладки мы можем использовать параметры onTrigger и onTrack, но имейте в виду, что это относится только к разработке, если в производстве onTrigger и onTrack не будут работать.

watchEffect(
   () => {
      console.log("todo", todo.value)
   },
   {
      onTrigger(e) {
         console.log("onTrigger", e)
      },
      onTrack(e) {
         console.log("onTrack", e)
      }
   }
)

Кроме того, есть также optionsflush , optionsflush значение по умолчанию равноpre, что означает, что оно будет выполнено до рендеринга компонента, мы можем изменить значение на post, что означает, что оно будет выполнено после рендеринга компонента.

watchEffect(
   () => {
      console.log("todo", todo.value)
   },
   {
      flush: 'post'
   }
)

Часть 4 — Крючки жизненного цикла

Жизненный цикл Composition API не слишком отличается от Options API, есть несколько жизненных циклов, которые нам нужно понять:

  • onBeforeMount - вызывается перед началом монтирования
  • onMounted - вызывается при монтировании компонента
  • onBeforeUpdate - вызывается при изменении реактивных данных и перед повторным рендерингом
  • onUpdated - вызывается при изменении реактивных данных и после повторного рендеринга
  • onBeforeUnmount — вызывается перед уничтожением экземпляра Vue.
  • onUnmounted — вызывается после уничтожения экземпляра
  • onActivated - вызывается при активации компонента поддержки активности
  • onDeactivated — вызывается при деактивации компонента поддержки активности.
  • onErrorCaptured — вызывается при перехвате ошибки из дочернего компонента

может быть, некоторые из нас спросят, в API параметров есть жизненный цикл created и beforeCreated, а жизненный цикл Composition API удален created и beforeCreated? Ответ заключается в том, что жизненные циклы created и beforeCreated заменены на setup(), вот пример того, как их использовать.

//Options API
export default {
   data() { 
     return { 
       val: 'hello world'    
     }
   },
   created() {     
     console.log('Value of val is: ' + this.val)   
   }
}

если вы используете Composition API, это будет выглядеть так:

import { ref } from 'vue'

export default {
   setup() {    
     const val = ref('hello world') 
     console.log('Value of val is: ' + val.value)       
     return {         
       val
     }
   }
}

Имейте в виду, что если вы хотите использовать onMounted onUpdated другие хуки, не забудьте сначала их импортировать.

import { onMounted, onUpdated } from 'vue';

Кроме того, для отладки мы можем использовать хуки onRenderTriggered и onRenderTriggered, подробнее можно прочитать в документации здесь.

Часть 5 — Компонент (Props & Emit)

props и emit используются для передачи данных между компонентами. props используются для отправки данных из родительского компонента в дочерний компонент. При этом emit можно использовать как триггерное событие для передачи данных из дочернего компонента в родительский.

//called from parent component
<list-todo
   :todos="todos.list"
   @delete-todo="deleteTodo"
/>

мы можем использовать свойства доступа и использовать emit в дочернем компоненте следующим образом:

import { onMounted } from "vue"
export default {
   props: {
     todos: {
       type: Array,
       default: [],
     }
   },
   setup(props, { attrs, slots, emit }) {
      const handleDeleteTodo = (index) => {
         emit('delete-todo', index)
      }
      
      onMounted(() => {
         console.log("data from parent : ", props.todos)
      })
     
      return {
         handleDeleteTodo,
      }
   }
}

нужно помнить, что setup() имеет два аргумента, а именно props и context. context можно деструктурировать в { attrs, slots, emit, expose }, мы можем излучать, используя context

emit('eventName', [argumen])

возможно, это то, что я могу написать, вы можете прочитать полный код на моем GitHub по этой ссылке. Надеюсь, это будет полезно. Если у вас есть какие-либо вопросы или предложения, свяжитесь со мной по адресу https://dikiharifwibowo.github.io/.

Использованная литература.