Понимание новой системы реактивности в Vue 3

Понимание новой системы реактивности в Vue 3 Изучение

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

Система реактивности — это механизм, который автоматически синхронизирует источник данных (модель) со слоем представления данных (представления). Каждый раз, когда модель изменяется, вид перерисовывается заново, чтобы отразить изменения.

В качестве примера возьмем простой редактор Markdown. Обычно он имеет две панели: одну для написания кода Markdown (который изменяет базовую модель) и одну для предварительного просмотра скомпилированного HTML (который показывает обновленное представление). Когда вы пишете что-либо в области письма, это сразу же автоматически отображается на панели предварительного просмотра. Конечно, это всего лишь простой пример. Часто все бывает намного сложнее.

Во многих случаях данные, которые мы хотим отобразить, зависят от некоторых других данных. В таком сценарии зависимости отслеживаются, и данные обновляются соответствующим образом. Например, предположим, что у нас есть fullNameсвойство, которое зависит от firstNameи lastNameсвойств. При изменении любой из его зависимостей fullNameсвойство автоматически переоценивается, и результат отображается в представлении.

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

Краткое исследование реактивности Vue 2

Реактивность в Vue 2 более или менее «скрыта». Что бы мы ни добавили в dataобъект, Vue неявно делает его реактивным. С одной стороны, это облегчает работу разработчика, но с другой — снижает гибкость.

Читайте также:  Что должно быть в портфолио веб-разработчика?

За кулисами Vue 2 использует ES5 Object.defineProperty () для преобразования всех dataсвойств объекта в геттеры и сеттеры. Для каждого экземпляра компонента Vue создает экземпляр наблюдателя зависимостей. Любые свойства, собранные / отслеживаемые как зависимости во время рендеринга компонента, записываются наблюдателем. Позже, когда запускается установщик зависимости, наблюдатель получает уведомление, и компонент повторно визуализирует и обновляет представление. В основном так и работает вся магия. К сожалению, есть некоторые оговорки.

Предостережения при обнаружении изменений

Из-за ограничений Object.defineProperty()есть некоторые изменения данных, которые Vue не может обнаружить. Это включает:

  • добавление / удаление свойства в / из объекта (например, obj.newKey = value)
  • установка элементов массива по индексу (например, arr[index] = newValue)
  • изменение длины массива (например, arr.length = newLength)

К счастью, чтобы справиться с этими ограничениями, Vue предоставляет нам метод API Vue.set, который добавляет свойство к реактивному объекту, гарантируя, что новое свойство также является реактивным и, таким образом, запускает обновления представления.

Давайте рассмотрим вышеуказанные случаи на следующем примере:

<div id="app">
  <h1>Hello! My name is {{ person.name }}. I'm {{ person.age }} years old.</h1>
  <button @click="addAgeProperty">Add "age" property</button>
  <p>Here are my favorite activities:</p>
  <ul>
    <li v-for="item, index in activities" :key="index">
      {{ item }}
      <button @click="editActivity(index)">Edit</button>
    </li>
  </ul>
  <button @click="clearActivities">Clear the activities list</button>
</div>
const App = new Vue({
  el: '#app',
  data: {
    person: {
      name: "David"
    },
    activities: [
      "Reading books",
      "Listening music",
      "Watching TV"
    ]
  },
  methods: { 
    // 1. Add a new property to an object
    addAgeProperty() {
      this.person.age = 30
    },
    // 2. Setting an array item by index
    editActivity(index) {
      const newValue = prompt('Input a new value')
      if (newValue) {
        this.activities[index] = newValue
      }
    },
    // 3. Modifying the length of the array
    clearActivities() { 
      this.activities.length = 0 
    }
  }
});

Вот пример CodePen

В приведенном выше примере мы видим, что ни один из трех методов не работает. Мы не можем добавить к personобъекту новое свойство. Мы не можем редактировать элемент из activitiesмассива, используя его индекс. И мы не можем изменить длину activitiesмассива.

Конечно, для этих случаев есть обходные пути, и мы рассмотрим их в следующем примере:

const App = new Vue({
  el: '#app',
  data: {
    person: {
      name: "David"
    },
    activities: [
      "Reading books",
      "Listening music",
      "Watching TV"
    ]
  },
  methods: { 
    // 1. Adding a new property to the object
    addAgeProperty() {
      Vue.set(this.person, 'age', 30)
    },
    // 2. Setting an array item by index
    editActivity(index) {
      const newValue = prompt('Input a new value')
      if (newValue) {
        Vue.set(this.activities, index, newValue)
      }
    },
    // 3. Modifying the length of the array
    clearActivities() { 
      this.activities.splice(0)
    }
  }
});

Вот пример CodePen

В этом примере мы используем Vue.setметод API для добавления нового ageсвойства к personобъекту и для выбора / изменения определенного элемента из массива действий. В последнем случае мы просто используем метод встроенного splice()массива JavaScript.

Как мы видим, это работает, но это немного взломано и приводит к несогласованности в кодовой базе. К счастью, в Vue 3 это было решено. Давайте посмотрим на магию в действии на следующем примере:

const App = {
  data() {
    return {
      person: {
        name: "David"
      },
      activities: [
        "Reading books",
        "Listening music",
        "Watching TV"
      ]
    }
  },
  methods: { 
    // 1. Adding a new property to the object
    addAgeProperty() {
      this.person.age = 30
    },
    // 2. Setting an array item by index
    editActivity(index) {
      const newValue = prompt('Input a new value')
      if (newValue) {
        this.activities[index] = newValue
      }
    },
    // 3. Modifying the length of the array
    clearActivities() { 
      this.activities.length = 0 
    }
  }
}

Vue.createApp(App).mount('#app')

Вот пример CodePen

В этом примере, который использует Vue 3, мы возвращаемся к встроенным функциям JavaScript, используемым в первом примере, и теперь все методы работают как шарм.

В Vue 2.6 был представлен метод API Vue.observable (). Он до некоторой степени раскрывает систему реактивности, позволяющую разработчикам явно делать объекты реактивными. Фактически, это тот же самый метод, который Vue использует для внутренней оболочки dataобъекта и полезен для создания минимального межкомпонентного хранилища состояний для простых сценариев. Но, несмотря на свою полезность, этот единственный метод не может сравниться по мощности и гибкости с полным, многофункциональным API реактивности, который поставляется с Vue 3. И мы увидим почему в следующих разделах.

Примечание. Object.defineProperty()Vue 2 не поддерживает IE8 и более ранние версии, так как это функция только для ES5 и без нее.

Как работает реактивность Vue 3

Система реактивности в Vue 3 была полностью переписана, чтобы использовать преимущества ES6 Proxy и Reflect API. Новая версия предоставляет многофункциональный API реактивности, который делает систему гораздо более гибкой и мощной, чем раньше.

Proxy API позволяет разработчикам перехватывать и изменять низкоуровневые операции над целевым объектом. Прокси-сервер — это клон / оболочка объекта (называемого целью) и предлагает специальные функции (называемые ловушками ), которые реагируют на определенные операции и переопределяют встроенное поведение объектов JavaScript. Если вам все еще нужно использовать поведение по умолчанию, вы можете использовать соответствующий API Reflection, методы которого, как следует из названия, отражают методы Proxy API. Давайте рассмотрим пример, чтобы увидеть, как эти API используются в Vue 3:

let person = {
  name: "David",
  age: 27
};

const handler = {
  get(target, property, receiver) {
    // track(target, property)
    console.log(property) // output: name
    return Reflect.get(target, property, receiver)
  },
  set(target, property, value, receiver) {
    // trigger(target, property)
    console.log(`${property}: ${value}`) // output: "age: 30" and "hobby: Programming"
    return Reflect.set(target, property, value, receiver)
  }
}

let proxy = new Proxy(person, handler);   

console.log(person)

// get (reading a property value)
console.log(proxy.name)  // output: David

// set (writing to a property)
proxy.age = 30;

// set (creating a new property)
proxy.hobby = "Programming";

console.log(person) 

Вот пример CodePen

Для создания нового прокси мы используем new Proxy(target, handler)конструктор. Он принимает два аргумента: целевой объект ( personобъект) и объект-обработчик, который определяет, какие операции будут перехвачены ( getи setоперации). В handlerобъекте, мы используем getи setловушки, чтобы отслеживать, когда свойство считывается и когда свойство изменяется / добавлено. Мы устанавливаем консольные операторы, чтобы гарантировать правильную работу методов.

В getи setловушки принимают следующие аргументы:

  • target: целевой объект, который обернут прокси
  • property: название свойства
  • value: значение свойства (этот аргумент используется только для операций с множествами)
  • receiver: объект, над которым выполняется операция (обычно прокси)

Методы Reflect API принимают те же аргументы, что и соответствующие им прокси-методы. Они используются для реализации поведения по умолчанию для данных операций, которое для getловушки возвращает имя свойства, а для setловушки возвращается, trueесли свойство было установлено или falseнет.

Комментарии track()и trigger()функции специфичны для Vue и используются для отслеживания, когда свойство читается и когда свойство изменяется / добавляется. В результате Vue повторно запускает код, использующий это свойство.

В последней части примера мы используем консольный оператор для вывода исходного personобъекта. Затем мы используем еще одно заявление, чтобы прочитать свойство nameэтого proxyобъекта. Затем мы модифицируем ageсвойство и создаем новое hobbyсвойство. Наконец, мы personснова выводим объект, чтобы убедиться, что он был обновлен правильно.

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

При использовании реактивности Vue 3 также следует учитывать несколько моментов:

  • работает только в браузерах, поддерживающих ES6 +
  • реактивный прокси не равен исходному объекту

Изучение Vue 3 Reactivity API

Наконец, мы подошли к самому API реактивности Vue 3. В следующих разделах мы рассмотрим методы API, разделенные на логические группы. Я объединяю методы в группы, потому что думаю, что их легче запомнить, если они представлены таким образом. Начнем с основ.

Основные методы

В первую группу входят самые основные методы контроля реактивности данных:

  • ref принимает примитивное значение или простой объект и возвращает реактивный и изменяемый объект ref. Объект ref имеет только одно свойство value, указывающее на примитивное значение или простой объект.
  • reactive принимает объект и возвращает реактивную копию объекта. Преобразование является глубоким и затрагивает все вложенные свойства.
  • readonl yпринимает ссылку или объект (простой или реактивный) и возвращает исходному объекту только для чтения. Преобразование является глубоким и затрагивает все вложенные свойства.
  • markRaw возвращает сам объект и предотвращает его преобразование в прокси-объект.

Давайте теперь посмотрим на эти методы в действии:

<h1>Hello, Vue 3 Reactivity API! :)</h1>
<hr>
<p><strong>Counter:</strong> {{ counter }}</p>
<button@click="counter++">+ Increment counter</button>
<br><br>
<button@click="counter--">- Decrement counter</button>
<hr>
<h3>Hello! My name is <mark>{{ person.name }}</mark>. I'm <mark>{{ person.age }}</mark> years old.</h3>
<p>Edit person's name
  <inputv-model="person.name" placeholder="name" /> and age
  <inputv-model="person.age" placeholder="age" />
</p>
<hr>
<p><strong>PI:</strong> {{ math.PI }}</p>
<button@click="math.PI = 6.28">Double PI</button> <span>(The console output after the button is clicked: <em>"Set operation on key 'PI' failed: target is readonly."</em>)</span>
<hr>
<h3>Alphabet Numbers</h3>
<table>
  <tr>
    <th>Letter</th>
    <th>Number</th>
  </tr>
  <trv-for="(value, key) in alphabetNumbers">
    <td>{{ key }}</td>
    <td>{{ value }}</td>
  </tr>
</table>
<br>
<button@click="alphabetNumbers.B = 3">Change the value of B to 3</button><span> (Actually the letter B <em>is</em> changed to number 3 - <button@click="showValue">Show the value of B</button>, but it's <em>not</em> tracked by Vue.)</span>

 

import { ref, reactive, readonly, markRaw, isRef, isReactive, isReadonly, isProxy, onMounted } from 'vue';

export default {
  setup () {
    const counter = ref(0)
    const person = reactive({
      name: 'David',
      age: 36
    })
    const math = readonly({
      PI: 3.14
    })
    const alphabetNumbers = markRaw({
      A: 1,
      B: 2,
      C: 3
    })

    const showValue = () => {
      alert(`The value of B is ${alphabetNumbers.B}`)
    }

    onMounted(() => {
      console.log(isRef(counter)) // true
      console.log(isReactive(person)) // true
      console.log(isReadonly(math)) // true
      console.log(isProxy(alphabetNumbers)) // false
    })

    return {
      counter,
      person,
      math,
      alphabetNumbers,
      showValue
    }
  }
};

В этом примере мы исследуем использование четырех основных методов определения реактивности.

Сначала мы создаем counter объект ref со значением 0. Затем в представлении мы помещаем две кнопки, которые увеличивают и уменьшают значение счетчика. Когда мы используем эти кнопки, мы видим, что счетчик действительно реагирует.

Во-вторых, мы создаем personреактивный объект. Затем в представление мы помещаем два элемента управления вводом для редактирования человека nameи человека ageсоответственно. Когда мы редактируем свойства человека, они немедленно обновляются.

В-третьих, мы создаем mathобъект только для чтения. Тогда, по мнению, мы устанавливаем кнопку для удвоения значения math«S PIсобственности. Но когда мы нажимаем кнопку, в консоли отображается сообщение об ошибке, говорящее нам, что объект доступен только для чтения и что мы не можем изменять его свойства.

Наконец, мы создаем alphabetNumbersобъект, который не хотим преобразовывать в прокси, и помечаем его как необработанный. Он содержит все буквы алфавита с соответствующими им номерами (для краткости здесь используются только первые три буквы). Этот порядок вряд ли будет изменен, поэтому мы намеренно оставляем этот объект простым, что хорошо для производительности. Мы визуализируем содержимое объекта в таблице и устанавливаем кнопку, которая изменяет значение Bсвойства на 3. Мы делаем это, чтобы показать, что, хотя объект можно изменить, это не приводит к повторному рендерингу представления.

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

Наконец, мы используем методы проверки типа, описанные в следующем разделе, для тестирования и определения типа каждого созданного нами объекта. Мы запускаем эти проверки при первоначальной визуализации приложения с помощью onMounted()ловушки жизненного цикла.

Методы проверки типа

В эту группу входят все четыре упомянутых выше средства проверки типов:

  • isRef проверяет, является ли значение объектом ref.
  • isReactive проверяет, является ли объект реактивным прокси-сервером, созданным reactiveили созданным readonlyпутем обертывания другого прокси-сервера, созданного reactive.
  • isReadonly проверяет, является ли объект прокси-сервером только для чтения, созданным readonly.
  • isProxy проверяет, является ли объект прокси-сервером, созданным reactiveили readonly.

Дополнительные методы ссылок

Эта группа содержит дополнительные методы ref:

  • unref возвращает значение ссылки.
  • triggerRefвыполняет любые эффекты, привязанные к shallowRefобъекту вручную.
  • customRef создает настраиваемую ссылку с явным контролем над отслеживанием ее зависимостей и запуском обновлений.

Мелкие методы

Методы этой группы являются «мелкими» эквивалентами ref, reactivityи readonly:

  • shallowRefсоздает ссылку, которая отслеживает только его valueсвойство, не делая его значение реактивным.
  • shallowReactive создает реактивный прокси, который отслеживает только свои собственные свойства, за исключением вложенных объектов.
  • shallowReadonly создает прокси только для чтения, который делает только свои собственные свойства доступными только для чтения, за исключением вложенных объектов.

Давайте упростим понимание этих методов, рассмотрев следующий пример:

<h1>Hello, Vue 3 Reactivity API! :)</h1>
<hr>
<h2>Shallow Ref</h2>
<p><strong>Settings:</strong> {{settings}}  
  <br><br>
  Width: <inputv-model="settings.width" /> 
  Height: <inputv-model="settings.height" />
  <br><br>
  <button@click="settings = { width: 80, height: 80 }">
    Change the settings' value
  </button>
</p>
<hr>
<h2>Shallow Reactive</h2>
<p><strong>SettingsA:</strong> {{settingsA}}
  <br><br>
  Width: <inputv-model="settingsA.width" /> 
  Height: <inputv-model="settingsA.height" />
  <br><br>
  X: <inputv-model="settingsA.coords.x" /> 
  Y: <inputv-model="settingsA.coords.y" />
</p>
<hr>
<h2>Shallow Readonly</h2>
<p><strong>SettingsB:</strong> {{settingsB}} 
  <br><br>
  Width: <inputv-model="settingsB.width" /> 
  Height: <inputv-model="settingsB.height" />
  <br><br>
  <span>(The console output after trying to change the <strong>width</strong> or <strong>height</strong> is: <em>"Set operation on key 'width/height' failed: target is readonly."</em>)</span>
  <br><br>
  X: <inputv-model="settingsB.coords.x" /> 
  Y: <inputv-model="settingsB.coords.y" />
</p>

 

import {ref, shallowRef, shallowReactive, shallowReadonly, isRef, isReactive, isReadonly, onMounted } from 'vue';

export default {
  setup () {
    const settings = shallowRef({
      width: 100,
      height: 60
    })
    const settingsA = shallowReactive({
      width: 110,
      height: 70,
      coords: {
        x: 10,
        y: 20
      }
    })
    const settingsB = shallowReadonly({
      width: 120,
      height: 80,
      coords: {
        x: 20,
        y: 40
      }
    })

    onMounted(() => {
      console.log(isReactive(settings)) // false
      console.log(isReactive(settingsA)) // true
      console.log(isReactive(settingsA.coords)) // false
      console.log(isReadonly(settingsB)) // true       
      console.log(isReadonly(settingsB.coords)) // false
    })

    return {
      settings,
      settingsA,
      settingsB
    }
  }
}; 

Этот пример начинается с создания settingsмелкого объекта ссылки. Тогда, по мнению, мы добавим два входных элементов управления для редактирования его widthи heightсвойства. Но когда мы пытаемся их изменить, мы видим, что они не обновляются. Чтобы исправить это, мы добавляем кнопку, которая изменяет весь объект со всеми его свойствами. Теперь это работает. Это связано с тем, что valueсодержимое ( widthи heightкак отдельные свойства) не преобразуется в реактивный объект, но изменение value(объекта в целом) по-прежнему отслеживается.

Далее мы создаем settingsAмелкую реактивную прокси, который содержит widthи heightсвойство и вложенный coordsобъект с xи yсвойствами. Затем в представлении мы устанавливаем элемент управления вводом для каждого свойства. Когда мы изменить widthи heightсвойства, мы видим, что они реактивно обновляются. Но когда мы пытаемся изменить xи yсвойство, мы видим, что они не отслеживаются.

Наконец, мы создаем settingsBнеглубокий объект только для чтения с теми же свойствами, что и settingsA. Здесь, когда мы пытаемся изменить свойство widthили height, в консоли отображается сообщение об ошибке, говорящее нам, что объект доступен только для чтения, и мы не можем изменить его свойства. С другой стороны, xи yсвойства могут быть изменены без проблем.

Вложенный coordsобъект из обоих последних примеров не затрагивается преобразованием, и он остается открытым. Это означает, что его можно свободно изменять, но ни одна из его модификаций не будет отслеживаться Vue.

Методы преобразования

Следующие три метода используются для преобразования прокси в ссылки или простой объект:

  • toRefсоздает ссылку на свойство исходного реактивного объекта. Ссылка сохраняет реактивное соединение со своим исходным свойством.
  • toRefsпреобразует реактивный объект в простой объект. Каждое свойство простого объекта — это ссылка, указывающая на соответствующее свойство исходного объекта.
  • toRawвозвращает сырой, простой объект reactiveили readonlyпрокси.

Давайте посмотрим, как эти преобразования работают на следующем примере:

<h1>Hello, Vue 3 Reactivity API! :)</h1>
<hr>
<h3>Hello! My name is <mark>{{ person.name }}</mark>. 
  I'm <mark>{{ person.age }}</mark> years old. 
  My hobby is programming.</h3>
<hr>
<h2>To Ref</h2>
<p> 
  Name (ref): <input v-model="name" /> 
  Person's name: <input v-model="person.name" />
</p>
<hr>
<h2>To Refs</h2>
<p> 
  PersonDetails' age (ref): <input v-model="personDetails.age.value" /> 
  Person's age: <input v-model="person.age" />
</p>
<hr>
<h2>To Raw</h2>
<p> 
  <strong>RawPerson's hobby:</strong> {{rawPerson.hobby}}
  <br><br>
  RawPerson's hobby: <input v-model="rawPerson.hobby" />
</p>

 

import { reactive, toRef, toRefs, toRaw, isReactive, isRef, onMounted } from 'vue';

export default {
  setup () {
    const person = reactive({
      name: 'David',
      age: 30,
      hobby: 'programming'
    })
    const name = toRef(person, 'name')
    const personDetails = toRefs(person)
    const rawPerson = toRaw(person)

    onMounted(() => {
      console.log(isRef(name)) // true
      console.log(isRef(personDetails.age)) // true
      console.log(isReactive(rawPerson)) // false
    })

    return {
      person,
      name,
      personDetails,
      rawPerson
    }
  }
};

В этом примере мы сначала создаем базовый personреактивный объект, который мы будем использовать в качестве исходного объекта.

Затем мы конвертируем nameсвойство человека в одноименную ссылку. Затем в представлении мы добавляем два элемента управления вводом — один для nameссылки и один для nameсвойства человека. Когда мы изменяем один из них, другой обновляется соответствующим образом, поэтому реактивная связь между ними сохраняется.

Затем мы конвертируем все свойства человека в отдельные ссылки, содержащиеся в personDetailsобъекте. Затем в представлении мы снова добавляем два элемента управления вводом, чтобы проверить одну из только что созданных ссылок. Как мы видим, объект personDetails ageполностью синхронизирован со ageсвойством человека, как и в предыдущем примере.

Наконец, мы преобразовываем personобъект реактивности в rawPersonпростой объект. Затем в представлении мы добавляем элемент управления вводом для редактирования свойства rawPerson hobby. Но, как мы видим, преобразованный объект не отслеживается Vue.

Вычисляемые и наблюдаемые методы

Последняя группа методов предназначена для вычисления сложных значений и «слежки» за определенными значениями:

  • computed принимает в качестве аргумента функцию получения и возвращает неизменяемый реактивный объект ссылки.
  • watchEffect немедленно запускает функцию и реактивно отслеживает ее зависимости и повторно запускает ее всякий раз, когда зависимости изменяются.
  • watchявляется точным эквивалентом API опций this.$watch и соответствующей watchопции. Он наблюдает за конкретным источником данных и применяет побочные эффекты в функции обратного вызова при изменении наблюдаемого источника.

Рассмотрим следующий пример:

<h1>Hello, Vue 3 Reactivity API! :)</h1>
<hr>
<h3>Hello! My name is <mark>{{ fullName }}</mark>.</h3>
<p> 
  First Name: <input v-model="firstName" /> 
  Last Name: <input v-model="lastName" />
</p>
<hr>
<strong>Volume:</strong> {{volume}}
<br><br>
<button @click="volume++">+ Increment volume</button>
<hr>
<strong>State:</strong> {{state}}
<br><br>
<button @click="state = state == 'playing' ? 'paused' : 'playing' ">Change state</button>

 

import { ref, computed, watch, watchEffect } from 'vue';

export default {
  setup () {
    // computed
    const firstName = ref('David')
    const lastName = ref('Wilson')
    const fullName = computed(() => {
      return firstName.value + ' ' + lastName.value
    })
    // watchEffect
    const volume = ref(0)
    watchEffect(() => {
      if (volume.value != 0 && volume.value % 3 == 0) {
          alert("The volume's value can be divided into 3")
        }
    })
    // watch
    const state = ref('playing')
    watch(state, (newValue, oldValue) =>
      alert(`The state was changed from ${oldValue} to ${newValue}`)
    )

    return {
      firstName,
      lastName,
      fullName,
      volume,
      state
    }
  }
}; 

В этом примере мы создаем fullNameвычисляемую переменную, вычисление которой основано на значениях firstNameи lastNamerefs. Затем в представлении мы добавляем два элемента управления вводом для редактирования двух частей полного имени. И, как мы видим, когда мы изменяем какую-либо часть, fullNameвычисляется заново, а результат обновляется.

Далее мы создаем volumeреф и устанавливаем для него эффект наблюдения. Каждый раз, когда volumeизменяется, эффект запускает функцию обратного вызова. Чтобы доказать это, мы добавляем в представление кнопку, увеличивающую громкость на единицу. Мы устанавливаем условие в функции обратного вызова, которое проверяет, можно ли разделить значение тома на 3, и когда оно возвращает true, отображается предупреждающее сообщение. Эффект запускается один раз при запуске приложения и установке значения громкости, а затем снова при каждом изменении значения громкости.

Наконец, мы создаем stateссылку и устанавливаем функцию наблюдения, чтобы отслеживать ее изменения. Как только stateизменения будут внесены, функция обратного вызова будет выполнена. В этом примере мы добавляем кнопку, которая переключает состояние между playingи paused. Каждый раз, когда это происходит, отображается предупреждающее сообщение.

watchEffectи watchвыглядят практически одинаково с точки зрения функциональности, но имеют некоторые отличия:

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

Как видите, API реактивности Vue 3 предлагает множество методов для различных случаев использования. API довольно большой, и в этом руководстве я изучил только основы. Для более глубокого изучения, подробностей и крайних случаев посетите документацию Reactivity API.

Заключение

В этой статье мы рассмотрели, что такое система реактивности и как она реализована в Vue 2 и Vue 3. Мы увидели, что у Vue 2 есть некоторые недостатки, которые успешно решены в Vue 3. Реактивность Vue 3 — это полная переработка на основе современного JavaScript. Особенности. Подведем итог его достоинствам и недостаткам.

Преимущества:

  • Его можно использовать как отдельный пакет. Вы можете использовать его, например, с React.
  • Он предлагает гораздо большую гибкость и мощность благодаря многофункциональному API.
  • Он поддерживает больше структур данных (Map, WeakMap, Set, WeakSet).
  • У него лучшая производительность. Только необходимые данные становятся реактивными.
  • Предостережения по поводу манипулирования данными из Vue 2 устранены.

Недостатки:

  • Он работает только в браузерах, поддерживающих ES6 +.
  • Реактивный прокси не равен исходному объекту с точки зрения сравнения идентичности ( ===).
  • Для этого требуется больше кода по сравнению с «автоматической» реактивностью Vue 2.

Суть в том, что реактивность Vue 3 — это гибкая и мощная система, которую могут использовать как разработчики Vue, так и разработчики, не использующие Vue. Каким бы ни был ваш случай, просто возьмите его и начните создавать потрясающие вещи.

Оцените статью
bestprogrammer.ru
Добавить комментарий

  1. Данила

    Очень крутая статья, но в тексте не хватает пробелов)

    Ответить