JavaScript

Почему в Vue 3 Composition API — reactive() будет считаться не нужным

Spread the love

В новом RFC в котором описано Vue Composition API, для создания реактивных переменных было представлены две новые функции ref и reactive. В нем было описаны их преимущества и недостатки, а так же сказано:
На данном этапе мы полагаем, что еще слишком рано называть лучшей практикой использование ref, а не reactive. Мы рекомендуем вам придерживаться стиля, который лучше соответствует вашей ментальной модели, из двух вариантов выше. Мы будем собирать отзывы пользователей в реальном мире и в конечном итоге предоставим более четкие рекомендации по этой теме.

Данная статья описывает одно из мнений, почему функция reactive() может быть не нужной. Само мнение очень интересно, с точки зрения изучения нового API.

Оригинальная статья:  Jason YuThought on Vue 3 Composition API — `reactive()` considered harmful


Спонсор поста RackStore — поставщик широкого спектра IT-услуг на базе сети дата-центров, расположенных в Москве. Размещение серверов в дата-центре (Colocation). Бесперебойное электроснабжение. Круглосуточная охрана и видеонаблюдение, климат-контроль, резервными источниками питания, высокоскоростные каналы связи с безлимитным трафиком. Возможность межоператорских соединений. Техническая поддержка 24/7 и SLA-гарантии. Дата центры Tier2+ и Tier3. Высококвалифицированные специалисты осуществляют круглосуточную техническую поддержку на территории ЦОД


Vue.js выделяется среди других фреймворков своей интуитивной реактивностью. Сomposition API Vue 3 собирается снять некоторые ограничения в Vue 2 и предоставить более явное API.

Краткое введение в Composition API

Есть два способа создания реактивных переменных:

  1. reactive()
  2. ref() / computed()

reactive()

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

Для примера:

// template: {{ state.a }} - {{ state.b }}
const state = reactive({ a: 3 })
// renders: 3 - undefined

state.a = 5
state.b = 'bye'
// renders: 5 - bye

Это работает точно так же, как data в Vue 2. За исключением того, что теперь мы можем добавлять к ним новые свойства, поскольку реактивность реализована с помощью прокси в Vue 3.

Ref

В Vue Composition API так же добавлен ref, который представляет собой просто объект с 1 свойством .value. Мы можем выразить его с помощью Typescript:

interface Ref<A> {
  value: A
}

Есть два способа использования refs:

  1. ref()
    • .value может иметь get/set.
  2. computed()
    • .value будет только для чтения, если не указан setter.

Для примера:

const countRef = ref(0) // { value: 0 }
const countPlusOneRef = computed(() => countRef.value + 1) // { value: 1 }
countRef.value = 5

/*
 * countRef is { value: 5 }
 * countPlusOneRef is { value: 6 } (readonly)
 */

reactive() это плохо; ref это хорошо.

Этот раздел статьи является только моим мнением о использование Composition API после создания нескольких проектов с его помощью. Попробуйте сами и дайте мне знать, если вы согласны или не согласны.

Прежде чем я сам не попробовал Composition API, я думал, что reactive() будет API, которое все будут использовать в конечном итоге, так как он не требует лишнего атрибута .value. Удивительно, но после создания нескольких проектов с Composition API, я ни разу не использовал reactive()!

Вот 3 причины почему:

  1. Удобствоref() позволяет объявить новую реактивную переменную на лету.
  2. Гибкостьref() разрешает полную замену объекта
  3. Ясность.value заставляет вас осознавать, то что вы делаете

1. Удобство

Composition api предлагается предоставить способ группировки кода в соответствии с их функцией в компоненте вместо их функции в Vue. Опции Vue Api 2.X группируют код в data, computed, methods, жизненные циклы и т. д. Это делает практически невозможным группирование кода по функциям. Взгляните на следующее изображение, на нем кода закрашен определенным цветом соответствие с решаемой задаче:

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

const state = reactive({
  count: 0,
  errorMessage: null,
})
setTimeout(() => state.count++, 1000)
watch(state.count, count => {
  if (count > 10) {
    state.errorMessage = 'Larger than 10.'
  }
})

Если мы будем использовать reactive() для хранения нескольких свойств. Легко попасть в ловушку группировки вещей по функциям, а не по свойствам. Скорее всего, вы будете прыгать по базе кода, чтобы изменить этот реактивный объект. Что сделает процесс разработки менее плавным.

const count = ref(0)
setTimeout(() => count.value++, 1000)

const errorMessage = ref(null)
watch(count, count => {
  if (count > 10) {
    errorMessage.value = 'Larger than 10.'
  }
})

С другой стороны, ref() позволяет нам вводить новые переменные на лету. Из приведенного выше примера я представляю переменные только по мере необходимости. Это делает процесс разработки намного более плавным и интуитивно понятным.

2. Гибкость

Сначала я думал, что единственная цель ref() состоит в том, чтобы примитивные значения были реактивными. Но также может быть очень удобно использовать ref() с объектами.

Рассмотрим:

const blogPosts = ref([])
blogPosts.value = await fetchBlogPosts()

Если мы хотим сделать то же самое с reactive, нам нужно вместо этого изменить массив.

const blogPosts = reactive([])
for (const post of (await fetchBlogPosts())) {
  blogPosts.push(post)
}

или с нашим «любимым» Array.prototype.splice()

const blogPosts = reactive([])
blogPosts.splice(0, 0, ...(await fetchBlogPosts()))

Как показано, с ref() проще работать так как в этом случае, вы можете просто заменить весь массив новым. Если это вас не убеждает, представьте, что blogPosts нужно разбить на страницы:

watch(page, page => {
  // remove everything from `blogPosts`
  while (blogPosts.length > 0) {
    blogPosts.pop()
  }

  // add everything from new page
  for (const post of (await fetchBlogPostsOnPage(page))) {
    blogPosts.push(post)
  }
})

или с нашим лучшим другом splice

watch(page, page => {
  blogPosts.splice(0, blogPosts.length, ...(await fetchBlogPostsOnPage(page)))
})

Но если мы используем ref()

watch(page, page => {
  blogPosts.value = await fetchBlogPostsOnPage(page)
})

Что очень гибко для работы.

3. Ясность

reactive() возвращает объект, с которым мы будем взаимодействовать так же, как мы взаимодействуем с другим нереактивным объектом. Это круто, но на практике это может сбить с толку, если мы имеем дело с другими нереактивными объектами.

watch(() => {
  if (human.name === 'Jason') {
    if (!partner.age) {
      partner.age = 30 
    }
  }
})

Мы не можем действительно сказать, будет ли реактивным human или partner. Но если мы отказываемся от использования reactive() и последовательно используем ref(), у нас не будет этой проблемы.

поначалу .value может показаться многословным; но он помогает напомнить нам, что мы имеем дело с реактивностью.

watch(() => {
  if (human.value.name === 'Jason') {
    if (!partner.age) {
      partner.age = 30 
    }
  }
})

Теперь становится очевидным, что human будет реактивным, а не partner.

Заключение

Приведенные выше замечания и мнения носят предварительный характер. Как вы думаете? Вы согласны, что ref() будет доминировать в Vue 3? Или вы думаете, что reactive() будет предпочтительным?

Дай мне знать в комментариях! Я хотел бы услышать больше ваших идей!

Была ли вам полезна эта статья?
[11 / 3.7]

Spread the love
Editorial Team

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago