Кодирование лучших составных частей: гибкие аргументы (2/5)
Эта серия познакомит вас с несколькими передовыми методами написания компонуемых объектов. Когда вы закончите, у вас будет четкое представление о создании твердых составных частей.
Автор: Майкл Тиссен
При использовании составных объектов в Vue.js иногда у вас уже есть ссылка, которую вы хотите использовать. В другое время вы этого не сделаете. В этой статье будет рассмотрен шаблон, который позволит вам использовать компонуемые объекты любым способом, что даст вам больше гибкости при написании приложений.
Это вторая статья в серии из пяти частей. Если вы еще не читали первую, приглашаю вас начать с начала. Эта серия познакомит вас с несколькими передовыми методами написания компонуемых объектов. Когда вы закончите, у вас будет четкое представление о создании твердых составных частей.
Вот некоторые передовые методы компоновки Vue, которые мы рассмотрим в этой статье:
- Как использовать параметр объекта параметров, чтобы сделать ваши компонуемые объекты более настраиваемыми
- Использование
ref
иunref
, чтобы сделать наши аргументы более гибкими 👈 мы здесь - Простой способ сделать возвращаемые значения более полезными
- Почему, начиная с интерфейса, ваши компонуемые компоненты становятся более надежными
- Как использовать асинхронный код без ожидания — сделать ваш код более понятным
Но сначала давайте убедимся, что мы все понимаем, что такое компонуемые.
Если вы уже прочитали предыдущую статью, вы можете перейти к следующему разделу.
Что такое компонуемый?
Согласно документации Vue, компонуемый — это функция, которая использует Vue Composition API для инкапсуляции и повторного использования логики с отслеживанием состояния.
Это означает, что любой код, использующий реактивность, можно превратить в компонуемый.
Вот простой пример компонуемого useMouse
из документации Vue.js:
import { ref, onMounted, onUnmounted } from 'vue'
export function useMouse() { const x = ref(0) const y = ref(0)
function update(event) { x.value = event.pageX y.value = event.pageY }
onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update))
return { x, y } }
Мы определяем наше состояние как refs
, а затем обновляем это состояние при каждом движении мыши. Возвращая ссылки x
и y
, мы можем использовать их внутри любого компонента (или даже другого компонуемого).
Вот как мы будем использовать этот компонуемый внутри компонента:
<template> X: {{ x }} Y: {{ y }} </template>
<script setup> import { useMouse } from './useMouse'; const { x, y } = useMouse(); </script>
Как видите, использование компонуемого useMouse
позволяет нам легко повторно использовать всю эту логику. С очень небольшим количеством дополнительного кода мы можем получить координаты мыши в нашем компоненте.
Теперь, когда мы находимся на одной странице, давайте посмотрим на первый шаблон, который поможет нам писать лучшие компонуемые объекты.
Используйте ref и unref для более гибких параметров.
Почти все компонуемые требуют в качестве входных данных какой-либо аргумент. Часто это реактивный ref
. Это также может быть примитивный тип Javascript, такой как строка, число или объект. Но мы хотим, чтобы наши компонуемые были еще более гибкими и пригодными для повторного использования, верно?
Вместо того, чтобы требовать либо ссылку или примитив, мы можем принять любой из них. Затем мы на лету преобразуем аргумент в то, что нам нужно:
// Works if we give it a ref we already have const countRef = ref(2); useCount(countRef); // Also works if we give it just a number const countRef = useCount(2);
Компонуемый элемент useTitle
, который мы видели в предыдущей статье, также применяет этот шаблон.
Когда вы передаете ссылку, она привязывается к названию документа. Затем для заголовка будет установлено значение этого ref
:
const title = ref('This is the title');
useTitle(title);
title.value = 'New title please';
Если вы передадите только строку, она создаст для вас новый ref
, а затем продолжит связывать его с заголовком документа:
const title = useTitle('This is the title');
title.value = 'New title please';
В этих надуманных примерах это не выглядит большой разницей. Однако, когда вы используете другие методы и составные объекты, у вас уже может быть ref
откуда-то еще. А может и нет. В любом случае, этот составной может адаптироваться к тому, что вам нужно.
Теперь давайте посмотрим, как заставить это работать в наших составных элементах.
Реализация гибких аргументов в составном
Чтобы заставить шаблон гибких аргументов работать, нам нужно использовать либо функцию ref
, либо функцию unref
для полученного аргумента:
// When we need to use a ref in the composable export default useMyComposable(input) { const ref = ref(input); }
// When we need to use a raw value in the composable export default useMyComposable(input) { const rawValue = unref(input); }
Функция ref
создаст для нас новый ref
. Но если мы передаем ему ref
, он просто возвращает нам это ref
:
// Create a new ref const myRef = ref(0);
// Get the same ref back assert(myRef === ref(myRef));
Функция unref
работает так же, но вместо этого она либо разворачивает ref
, либо возвращает нам наше примитивное значение:
// Unwrap to get the inner value const value = unref(myRef);
// Returns the same primitive value assert(value === unref(value));
Давайте посмотрим, как некоторые компонуемые элементы из VueUse реализуют этот шаблон. VueUse — это коллекция компоновок с открытым исходным кодом для Vue 3, и она очень хорошо написана. Это отличный ресурс, чтобы научиться писать великолепные составные части!
useTitle
Мы вернемся к составному элементу useTitle
, так как мы уже знакомы с ним.
Этот компонуемый объект позволяет нам передавать либо строку, либо ref
строки. Неважно, что мы предоставляем:
// Pass in a string const titleRef = useTitle('Initial title');
// Pass in a ref of a string const titleRef = ref('Initial title'); useTitle(titleRef);
В исходном коде вы можете видеть, что сразу после того, как мы деструктурировали наш объект параметров, мы создали title
ref. Здесь мы используем функцию ref
, которая позволяет нам использовать либо ref
, либо строку для создания ссылки title
:
// ...
const title = ref(newTitle ?? document?.title ?? null)
// ...
Синтаксис ??
— это нулевой оператор объединения — причудливо звучащее название для если значение слева нулевое или неопределенное, используйте значение справа. Итак, эта строка сначала пытается использовать newTitle
, но если это не определено, будет использоваться document.title
, а если это не определено, она сдастся и будет использовать null
.
Кое-что интересное для вас, знатоков TypeScript:
Используемая здесь переменная newTitle
имеет тип MaybeRef<string>
. Вот что тип определяется как:
type MaybeRef<T> = T | Ref<T>
Это определение типа означает, что тип MaybeRef<string>
может быть либо string
, либо Ref<string>
, который является ссылкой со строковым значением внутри.
Следующий составной объект, который мы рассмотрим, также использует этот тип для реализации этого шаблона.
useCssVar
Компонуемый useCssVar позволяет нам получить значение переменной CSS и использовать его в нашем приложении:
const backgroundColor = useCssVar('--background-color');
Однако, в отличие от useTitle
, здесь нам нужно строковое значение, чтобы мы могли найти переменную CSS в DOM. Используя функцию unref
, этот составной объект может обрабатывать как ссылки, так и передаваемые строки:
// Using a string const backgroundColor = useCssVar('--background-color');
// Using a ref const cssVarRef = ref('--background-color'); const backgroundColor = useCssVar(cssVarRef);
Глядя на исходный код, мы видим, что для этого используется функция unref
. На самом деле, он использует вспомогательную функцию под названием unrefElement
, чтобы убедиться, что мы получаем элемент DOM, а не просто экземпляр Vue.
Большинство составных объектов в VueUse реализуют этот шаблон, если вы хотите изучить его подробнее. Так что выбирайте тот, который выглядит интереснее, и погрузитесь в код!
Подведение итогов
Мы только что потратили некоторое время на изучение второго шаблона в серии, где мы можем использовать аргументы более гибко, разумно используя ref
и unref
в наших составных элементах. Компонуемый по-прежнему будет работать независимо от того, есть ли у вас ref
или просто необработанное значение Javascript. Он адаптируется к тому, как вы его используете!
Мы также рассмотрели, как библиотека VueUse реализует этот шаблон в компонуемых объектах useTitle
и useCssVar
. Компонуемый useTitle
использует функцию ref
, а useCssVar
использует функцию unref
, чтобы мы могли видеть оба варианта в действии.
В следующей статье мы рассмотрим шаблон для улучшения возвращаемых значений, сделав их динамическими. Мы узнаем, как мы можем вернуть либо одно значение, либо объект, в зависимости от того, что необходимо:
// Returns a single value const isDark = useDark();
// Returns an object of values const { counter, pause, resume, } = useInterval(1000, { controls: true });
Этот шаблон может значительно упростить использование составного объекта, особенно если большую часть времени вам нужно только одно значение.
Первоначально опубликовано на https://www.vuemastery.com 18 апреля 2022 г.