Русский
Русский
English
Статистика
Реклама

Vue 3.0

Перевод Какой будет новая версия Vuex?

27.12.2020 20:07:49 | Автор: admin
Vuex стейт менеджер для Vue приложений. Его следующая версия Vuex 4, которая практически готова к официальному релизу. Она добавит поддержку Vue 3, но не принесет никакой новой функциональности.

Несмотря на то, что Vuex считается отличным решением и многие разработчики выбирают его как основную библиотеку для управления состоянием, они надеются получить больше возможностей в будущих релизах. Поэтому, пока Vuex 4 только готовится к выходу, один из его разработчиков, Kia King Ishii (входит в состав core-команды) уже делится планами для следующей, 5 версии. Стоит заметить, что это только планы и некоторые вещи могут измениться, тем не менее основное направление уже похоже выбрано. О нем и пойдет речь.

С появлением Vue 3 и Сomposition API, разработчики стали создавать простые альтернативы. Например, в статье Вероятно вам не нужен Vuex демонстрируется простой, гибкий и надежный способ для создания сторов на основе Composition API совместно с provide/inject. Можно предположить, что этот и некоторые другие альтернативы вполне подойдут для небольших приложение, но как часто бывает, они имеют свои недостатки: документация, сообщество, соглашение в именовании, интеграция, инструменты разработчика.



Последний пункт имеет большое значение. Сейчас у Vue есть отличное расширение для браузера, помогающее в разработке и отладке. Отказ от него может стать большой потерей, особенно при создании больших приложений. Но к счастью, с Vuex 5 этого не произойдет. Что касается альтернативных подходов, они будут работать, но не принесут столько плюсов, как официальное решение. Поэтому давайте посмотрим, какие именно плюсы нам обещают.

Создание стора


Перед тем как делать что-то со стором, нам нужно его создать. Вo Vuex 4, это выглядит следующим образом:

import { createStore } from 'vuex'export const counterStore = createStore({  state: {    count: 0  },    getters: {    double (state) {      return state.count * 2    }  },    mutations: {    increment (state) {      state.count++    }  },    actions: {    increment (context) {      context.commit('increment')    }  }})

Стор все также состоит из 4 частей: состояние (state), где хранятся данные; геттеры (getters), предоставляющие вычисляемые состояния; мутации (mutations), необходимые для изменения состояния и экшены (actions), которые вызываются за пределами стора для выполнения операций над ним. Обычно экшены не просто вызывают мутацию (как в примере), а используются для выполнения асинхронных задач (потому что мутации должны быть синхронными) или реализуют какую-то более сложную логику. Как же будет выглядеть Vuex 5?

import { defineStore } from 'vuex'export const counterStore = defineStore({  name: 'counter',    state() {    return { count: 0 }  },    getters: {    double () {      return this.count * 2    }  },    actions: {    increment () {      this.count++    }  }})

Первое, что изменилось переименование createStore в defineStore. Чуть позже будет понятно почему. Следующее, появился параметр name для указания имени стора. До этого, мы разделяли сторы на модули, а имена модулей были в виде именованных объектов. Далее модули регистрировались в глобальном пространстве, из-за чего они не были самодостаточными и готовыми для переиспользования. В качестве решения, нужно было использовать параметр namespaced, чтобы не давать нескольким модулям реагировать на тот же тип мутаций и действий. Думаю многие сталкивались с этим, но ссылку на документацию я, тем не менее, добавлю. Теперь у нас нет модулей, каждый стор по-умолчанию отдельное и независимое хранилище.

После указания имени, нам нужно сделать state функцией, которая возвращает начальное состояние, а не просто устанавливает его. Это очень похоже на то, как выглядит data в компонентах. Изменения коснулись и геттеров, вместо state как параметра функции мы используем this, чтобы получить доступ к данным. Тот же подход применен и к экшенам, this вместо statе как параметра. И наконец, самое главное, мутации объединены с экшенами. Kia отмечал, что мутации довольно часто становятся простыми сеттерами, делая их многословными, видимо это и послужило причиной удаления. Он не упоминает, можно ли будет производить изменение состояния за пределам стора, например из компонентов. Тут, мы можем только сослаться на Flux паттерн, который не рекомендует этого делать и поощряет подход с изменением состояния именно из экшенов.

Дополнение: те, кто использует Composition API для создания компонентов, будут рады узнать что, существует способ создания стора в похожей манере.

import { ref, computed } from 'vue'import { defineStore } from 'vuex'export const counterStore = defineStore('counter', {  const count = ref(0)  const double = computed(() => count.value * 2)    function increment () {    count.value++  }  return { count, double, increment }  })

В примере выше, мы передали имя стора, в качестве первого аргумент defineStore. Оставшаяся же часть, привычный Composition API, а результат будет абсолютно таким же как в примере с классическим API.

Инициализация стора


Здесь нас ждут существенные изменения. Чтобы описать, как будет происходить инициализация стора в 5-ой версии, посмотрим как это происходит в 4-ой. Когда мы создаем стор через createStore, мы сразу же его инициализируем, чтобы затем использовать в app.use или напрямую.

import { createApp } from 'vue'import App from './App.vue'import store from './store'const app = createApp(App)app.use(store)app.mount('#app')// Теперь у всех компонентов есть доступ к `this.$store`// Или к `useStore()` в контексте Composition APIimport store from './store'store.state.count // -> 0store.commit('increment')store.dispatch('increment')store.getters.double // -> 4

В 5 версии, мы отдельно получаем доступ к каждому экземпляру Vuex, что дает гарантию независимости. Поэтому этот процесс выглядит иначе:

import { createApp } from 'vue'import { createVuex } from 'vuex'import App from './App.vue'const app = createApp(App)const vuex = createVuex()app.use(vuex)app.mount('#app')

Теперь все компоненты имеют возможность обращаться напрямую к любому экземпляру Vuex, вместо обращения к глобальному пространству. Взгляните на пример:

import { defineComponent } from 'vue'import store from './store'export default defineComponent({  name: 'App',  computed: {    counter () {      return this.$vuex.store(store)    }  }})

Вызов $vuex.store создает и инициализирует стор. Теперь, каждый раз общаясь к этому хранилищу через $vuex.store, вам будет возвращаться уже созданный экземпляр. В примере это this.counter, который мы можем использовать дальше в коде. Так же, можно инициализировать стор через createVuex().

И конечно, вариант для Composition API, где вместо $vuex.store используется useStore.

import { defineComponent } from 'vue'import { useStore } from 'vuex' // import useStoreimport store from './store'export default defineComponent({  setup () {    const counter = useStore(store)    return { counter }  }})

У описанного выше подхода (инициализация стора через компоненты) существуют как преимущества, так и недостатки. С одной стороны это разделение кода и возможность добавлять его только там, где это необходимо. С другой добавление зависимости (при том, что теперь нужно импортировать стор каждый раз, когда планируешь его использовать). Поэтому, если вы хотите использовать DI, то предлагается вариант с использованием provide:

import { createApp } from 'vue'import { createVuex } from 'vuex'import App from './App.vue'import store from './store'const app = createApp(App)const vuex = createVuex()app.use(vuex)app.provide('name', store)app.mount('#app')

И последующим пробрасыванием стора в компонент:

import { defineComponent } from 'vue'export default defineComponent({  name: 'App',  inject: ['name']})// Composition APIimport { defineComponent, inject } from 'vue'export default defineComponent({  setup () {    const store = inject('name')    return { store }  }})

Восторга от этого решения не так много, но оно выглядит более явно и гибко, чем текущий подход. Так же нельзя не сказать про дальнейшее использование. Сейчас это выглядит следующим образом:

store.state.count                // Statestore.getters.double            // Gettersstore.commit('increment')   // Mutationsstore.dispatch('increment')  // Actions

В новой версии ожидается:

store.count          // Statestore.double         // Gettersstore.increment()  // Actions

Все сущности (состояние, геттеры и экшены) доступны напрямую, делая работу с ними проще и логичнее. При этом убирая необходимость в использовании mapState, mapGetters, mapActions и mapMutations, а так же написания дополнительных вычисляемых свойства.

Совместное использование


Последние момент, который стоит рассмотреть компоновка. Мы помним, что во Vuex 5 у нас больше нет именованных модулей и каждый стор является отдельным и независимым. Это дает возможность импортировать их когда нужно и использовать данные по мере необходимости, прямо как компоненты. Появляется логичный вопрос, как использовать несколько сторов вместе? В 4 версии все еще существует глобальное пространство имен и нам нужно использовать rootGetters и rootState, чтобы обращаться к разным сторам в этой области (так же как и в 3 версии). Подход в Vuex 5 иной:

// store/greeter.jsimport { defineStore } from 'vuex'export default defineStore({  name: 'greeter',  state () {    return { greeting: 'Hello' }  }})// store/counter.jsimport { defineStore } from 'vuex'import greeterStore from './greeter'export default defineStore({  name: 'counter',  use () {    return { greeter: greeterStore }  },    state () {    return { count: 0 }  },    getters: {    greetingCount () {      return `${this.greeter.greeting} ${this.count}'    }  }})

Мы импортируем стор, затем регистрируем его через use, и тем самым получаем к нему доступ. Все выглядит еще проще если использовать Сomposition API:

// store/counter.jsimport { ref, computed } from 'vue'import { defineStore } from 'vuex'import greeterStore from './greeter'export default defineStore('counter', ({use}) => {  const greeter = use(greeterStore)  const count = 0  const greetingCount = computed(() => {    return  `${greeter.greeting} ${this.count}`  })  return { count, greetingCount }})

Единственное, что стоит здесь упомянуть, это use, который работает точно также как vuex.store и отвечает за правильную инициализацию сторов.

Поддержка TypeScript


Благодаря изменениям в API и уменьшению количества абстракций, поддержка TypeScript в 4 версии будет намного лучше, но нам все еще потребуется много ручной работы. Выход же 5 версии даст возможность добавлять типы, там где необходимо, и там где мы этого хотим.

Заключение


Vuex 5 выглядит многообещающе и именно так как многие и ожидают (устранение старых недочетов, добавление гибкости). Полный список обсуждений и мнения основной команды можно найти в Vue RFCs репозитории.
Подробнее..

Перевод Зависимости JavaScript Все, что вы когда-либо хотели знать, но боялись спросить

02.03.2021 16:05:07 | Автор: admin

Ваше подробное руководство по пяти типам зависимости

Привет, хабровчане. Для будущих учащихся на курсе "JavaScript Developer. Professional" подготовили перевод материала.

Также приглашаем всех желающих на открытый вебинар по теме
Vue 3 возможности новой версии одного из самых популярных фронтенд фреймворков. На занятии участники вместе с экспертом:
рассмотрят ключевые отличия в синтаксисе vue2 от vue3;
разберут, как работать с vue-router и VueX в новой версии фреймворка;
cоздадут проект на Vue 3 с нуля с помощью Vue-cli.


Независимо от того, являетесь ли Вы back-end разработчиком, работающим с Node.js, или front-end разработчиком, использующим Node.js только в качестве инструмента для пакетирования и комплектации, Вы наверняка наткнулись на систему зависимостей.

Но почему их 5 типов (да, это не опечатка, есть 5 типов зависимостей), и для какого случая они используются? На эти вопросы мы ответим сегодня, так что сядьте поудобнее и расслабьтесь, потому что это будет интересно.

. . .

Normal (runtime) dependencies (cтандартные (во время выполнения программы) зависимости)

Давайте начнем с простого, хорошо?

Стандартные зависимости это те, которые вы видите в списке "dependencies" в вашем файле package.json. В большинстве случаев они указывают только имя (для своего ключа) и версию (значение), а затем NPM (node package manager или любой другой менеджер пакетов) позаботится об их захвате из глобального регистра (на npmjs.org).

Однако, это еще не все. Вместо точного номера версии вашей зависимости вы можете указать:

  • Примерный вариант. Вы можете работать с обычными числовыми операторами сравнения, указывая версии больше одного определенного числа (т.е. >1.2.0 ), любой версии ниже или равной другому числу (т.е. <=1.2.0 ), а также можете обыгрывать любую из их комбинаций (т.е. >= , > , <) . Вы также можете указать эквивалентную версию с помощью оператора ~ перед номером версии (т.е. "lodash":"~1.2.2, который загрузит что угодно между 1.2.2 и 1.3.0 или, другими словами, только патчи). И мы также можем указать "совместимую" версию с другим номером, который использует semver для понимания совместимости (т.е. "lodash": "^1.2.0", которая не загрузит ничего, из того что включает в себя изменение с нарушением или отсутствием каких-либо функций).

  • URL-АДРЕС. Правильно, вы даже можете обойтись без версии и напрямую ссылаться на определенный URL, по сути загрузив этот модуль откуда-нибудь еще (например, с Github или напрямую скачав tarball-файл).

  • Локальный файл. Да, вы даже можете непосредственно обращаться к одному из ваших локальных файлов. Это очень удобно, если вы разрабатываете модуль и хотите протестировать его на проекте, прежде чем выпускать его на NPM. С помощью опции "Локальный файл" вы можете сделать ссылку на папку вашего локального модуля. Вы можете использовать как полный, так и частичный пути, при условии, что вы используете префикс-функцию с помощью file:// .

Когда ты будешь использовать стандартные зависимости?

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

Это может показаться простым, но если, например, ваш проект на самом деле является модулем, то вам нужно более внимательно разобраться в том, что это значит. Если ваш модуль предназначен для использования с другими проектами, такими как React или Babel, ваши зависимости не должны включать их, так как они, как предполагается, уже присутствуют, тем не менее, они все равно нужны (мы это увидим позже, где они появятся через секунду).

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

. . .

Peer dependencies (Равные зависимости)

Peer dependencies это особый вид зависимостей, в том смысле, что они предназначены для указания тех пакетов, которые требуются вашему проекту, или, вернее, с которыми он совместим. Тем не менее, вы можете не запрашивать их конкретно в своем коде.

Подождите, зависимость, которая вам не требуется? Я знаю, это звучит странно, но подумайте о плагине Babel, он нуждается в Babel в том смысле, что если его там нет, то он не сможет работать, однако, он может и не требовать Babel явно для чего-либо.

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

Когда ты будешь использовать Peer dependencies?

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

Другими словами:

  • Когда она вам нужна, но нет необходимости употреблять ее сразу и однозначно. Тогда это peer dependency.

  • Когда она вам нужна, но она уже должна быть установлена другим проектом. Тогда это peer dependency.

Примерами того, когда вы хотите использовать peerDependencies, являются:

  • Babel плагины. Ты хочешь декларировать такие же вещи, как и сам Babel, в качестве равной зависимости (peer dependency).

  • Express middleware packages (Экспресс-пакеты для промежуточной обработки): Это всего лишь один пример модуля NPM, который требует использования peer dependencies. Вы хотите определить приложение Express как зависимость, но не жесткую, в противном случае каждое промежуточное ПО (middleware) будет каждый раз инсталлировать всю структуру заново.

  • Если вы собираете Micro Frontend (Микрофронтенд), пытаясь решить, какие зависимости являются внешними (чтобы они не были связаны), а какие нет. Peer dependencies могут быть хорошим решением для этого.

  • Bit components. Если вы создаете и публикуете front-end компоненты, например, когда вы совместно используете React-компоненты на Bit (Github), вам нужно назначить react библиотеку как peer dependency. Это позволит удостовериться, что нужная библиотека доступна в хостинговом проекте без установки ее в качестве прямой зависимости от него.

Например, взгляните на этот React компонент, который я опубликовал некоторое время назад: это простая кнопка, которую можно выбрать (вы нажимаете на нее и она остается выбранной до тех пор, пока не будет нажата снова).

Снимок экрана component, как видно на Bits component hub.

Если вы установите его, вы получите полный код, который содержит файл package.json, в котором перечислены все peer dependencies:

Обратите внимание, что пакет не имеет прямой зависимости, несмотря на то, что для работы ему необходима React-библиотека.

Это также помогает сохранить размер нашего компонента как можно меньше (1KB) ничего лишнего не добавляется.

. . .

Dev Dependencies (Dev зависимости)

Имя говорит обо всем, не так ли? Я имею в виду, что так и должно быть, но когда имена действительно помогают нам, разработчикам, в нашей повседневной работе? Я точно знаю.

Зависимости процесса разработки (Development dependencies) предназначены для того, чтобы содержать только те модули, которые вы используете на этапе разработки вашего проекта.

Да, но есть и другие, например, инструменты для подшивки (linting tools), документация и тому подобное.

Дело в том, что если вы можете запустить проект без использования этого набора инструментов, тогда это dev dependency.

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

Подумайте об этом, в этом случае имеет смысл установить их, так как вы разрабатываете свой собственный проект. Но если вы устанавливаете свой проект внутри другого, то этот процесс будет игнорировать ваши dev dependencies.

Когда ты будешь использовать dev dependencies?

Любая зависимость, которая не требуется для производственного процесса, скорее всего, будет считаться dev dependencies (зависимости развития).

Дело в том, что это отлично работает для всех модулей, кроме вашего хост-проекта.

Все установленные внутри хост-проекта зависимости будут пропускать dev-зависимости модулей во время инсталляции, но всякий раз, когда вы повторно запускаете npm install в хост-проекте, он будет устанавливать заново все пропущенные ранее dev-зависимости модулей.

Поэтому рассмотрим использование Dev зависимостей только для пакетов и модулей, которые будут использоваться другими проектами.

. . .

Связанные зависимости (Bundled Dependencies)

Они предназначены для тех случаев, когда вы упаковываете свой проект в один файл. Это делается с помощью команды npm pack, которая превращает вашу папку в тарбол (tarball-файл).

Теперь, если вы сделаете это и добавите имена некоторых из ваших зависимостей в массив под названием bundledDependencies (забавный факт: если вы используете bundleDependencies, это тоже будет работать), то тарбол также будет содержать эти зависимости внутри этого массива.

{...   "dependencies": {    "lodash": "1.0.2",    "request": "4.0.1"  },  "bundledDependencies": ["lodash"]...}

Посмотрите на эту часть файла package.json, с такой установкой, при запуске команды npm pack вы получите файл tarball, также содержащий пакет lodash внутри.

Это очень удобно при распространении ваших пакетов в однофайловом формате (помните, что вы также можете указать их URL или локальный путь как стандартную зависимость).

. . .

Дополнительные зависимости (Optional dependencies)

Наконец, этот тип зависимостей такой же, как и обычные, они ведут себя и могут быть настроены точно таким же образом. Единственная разница? NPM не выйдет с ошибкой, в случае, если не сможет установить их.

Обычно, когда вы запускаете npm install и процесс не может установить обычную зависимость по какой-либо причине (будь то из-за сбоя в сети, не может найти файл, версию или что-нибудь ещё), то он выдаст ошибку и отменит процесс установки.

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

let foo = null;try {  foo = require("foo-dep");} catch (e) {  foo = require("./local-polyfill")}//... use foo from here on out

Когда вы будете использовать дополнительные зависимости (optional dependencies)?

Очевидный пример использования этого типа зависимостей когда вы используете ненадежный источник. Я спрашиваю, зачем это делать? Хороший вопрос. Понятия не имею, но вы определенно можете это сделать, единственная проблема в том, что вам нужно убедиться, что ваш код может с этим справиться, если отсутствуют зависимости.

Но другой интересный вариант использования, это установка действительно необязательных зависимостей (optional dependencies). Я имею в виду, что иногда у вас могут быть специфические для системы зависимости, для таких вещей, как совместимость с CI(Continuous Integration)-платформой. В таких сценариях, когда используете платформу, вы захотите установить эти зависимости, в другом случае, проигнорируете.

Для таких ситуаций можно использовать обычную npm install, когда вы используете полный набор зависимостей, а затем использовать npm install --no-optional, когда вы хотите избежать их. Таким образом, вы пропустите эти опции и сосредоточитесь только на обязательных зависимостях.

. . .

Каждый, кто когда-либо пользовался NPM в тот или иной момент, слышал о стандартных и dev-зависимостях. Остальные 3, однако, можно считать менее популярными собратьями.

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

Знали ли вы, что у вас так много вариантов? Оставьте комментарий ниже, если вы использовали некоторые из менее распространенных и расскажите нам, как вы их использовали!


Узнать подробнее о курсе "JavaScript Developer. Professional".

Смотреть открытый вебинар по теме Vue 3 возможности новой версии одного из самых популярных фронтенд фреймворков.

Подробнее..

VueUse обязательная библиотека для Vue 3

27.04.2021 22:20:31 | Автор: admin

Для тех, кто незнаком с этой библиотекой, советую попробовать, так она может де-факто стать стандартом для использования в проектах на Vue 3, как стала, например, библиотека lodash для почти любых проектов на js.

Остальные наверное уже успели заценить весь обширный функционал, который она предоставляет. Некоторые уже использовали ее на Vue 2, но далеко не все новые функции поддерживают старую версию. Арсенал библиотеки впечатляет, тут и простые утилиты вроде клика вне элемента, и различные интеграции с Firebase, Axios, Cookies, QR, локальным хранилищем, браузером, RxJS, анимации, геолокации, расширения для стандартных Vue-хуков, медиа-плеер и многое другое. Среди спонсоров отмечен сам Эван Ю, что как бы намекает. Библиотека регулярно получает обновления, баги закрываются, а сообщество растет. В общем у нее есть все для успеха.

В этой статье я расскажу только о 3 фичах, но, безусловно, и все остальные нуждаются во внимании.

onClickOutside клики вне элемента

С установкой библиотеки вы справитесь, я уверен, поэтому перейдем сразу к интересным вещам. Для разогрева рассмотрим простой хук, который отслеживает клики вне заданного элемента onClickOutside. Существует множество пакетов, которые предоставляют данный функционал, не считая бесчисленные велосипеды, которые писал наверное каждый. Обычно его реализуют через добавление пользовательской Vue-директивы к нужному элементу, например v-clickOutside, а вот использование хука необычно.

Я использовал этот хук в своей тудушке, в компоненте ToDoItem.vue:

<template>    <li ref="todoItem">      <input type="checkbox" />      <span        v-if="!editable"        @click="editable = !editable"      >        {{ todo.text ? todo.text : "Click to edit Todo" }}      </span>      <input        v-else        type="text"        :value="todo.text"        @keyup.enter="editable = !editable"      />    </li></template><script lang="ts">  import { defineComponent, PropType, ref } from "vue"  import ToDo from "@/models/ToDoModel"  import { onClickOutside } from "@vueuse/core"  export default defineComponent({    name: "TodoItem",    props: {      todo: {        type: Object as PropType<ToDo>,        required: true      }    },    setup() {      const todoItem = ref(null)      const editable = ref(false)      onClickOutside(todoItem, () => {        editable.value = false      })      return { todoItem, editable }    }  })</script>

Я удалил лишний код, чтобы не отвлекал, но все еще компонент достаточно большой. Обратите внимание на код, который находится внутри хука setup, сначала мы создаем пустую ссылку todoItem, которую вешаем на нужный элемент в шаблоне, а потом передаем первым параметром в хук onClickOutside, а вторым параметром коллбэк с нужными нам действиями. При клике на тег span, он заменится на тег input, а если кликнуть вне тега li с атрибутом ref="todoItem", то input сменится тегом span.

useStorage реактивное локальное хранилище

Следующая функция, о которой я расскажу, это useStorage. Эта функция создает реактивное локальное хранилище. Это очень удобно, так как никаких дополнительные манипуляции с хранилищем больше не потребуются. Данные будут сохранятся, обновляться и удаляться автоматически. Я применил эту функцию в Vuex для хранения записей со списком дел.

// @/store/index.tsimport { createStore } from 'vuex'import Note from '@/models/NoteModel'import { useStorage } from '@vueuse/core'const localStorageNotes: unknown = useStorage('my-notes', [] as Note[])export default createStore({  state: {    notes: localStorageNotes as Note[]  },  mutations: {                  addNote(state) {      state.notes.push(note)    },   // mutations  },  actions: {    // actions  },  getters: {    // getters  },  strict: true})

Первым параметром функция useStorage принимает ключ, под которым она будет сохранять ваши данные, а вторым их начальное значение. Полученную переменную localStorageNotes передаем в state.notes. Массив notes можно использовать как обычно, например добавлять новую запись в мутациях. Теперь записи будут сохраняться даже после перегрузки страницы и самого браузера.

При написании этого кода TypeScript начал ругаться на отсутствие типа у переменной localStorageNotes. Этого следовала ожидать, так как эта переменная создается с помощью ref и не создана для использования вне хука setup. Я не нашел другого решения, кроме как присвоить ей значение any или unknown. Код работает, но выглядит не очень. Если кто знает лучшее решение, подскажите в комментариях. Будем надеяться, что авторы библиотеки создадут лучшую интеграцию с Vuex, где эта функциональность так необходима.

Для сравнения также полезно ознакомиться с примером использования useStorage от авторов. Разница в том, что в setup работать с реактивным хранилищем нужно не напрямую, а через его свойство value. В html-шаблоне же, все как обычно.\

useRefHistory история изменений

useRefHistory хук который позволит записывать историю изменений данных и предоставляет undo/redo функциональность. Я использовал ее для создания кнопок Undo и Redo на странице создания и редактирования записи со списком дел. Так как переменная currentNote, которая отвечает за хранение редактируемой записи, тоже находится во Vuex-хранилище. Я так же использовал ее именно там и так же получил ошибку типизации. Рассмотрим код получше:

import { createStore } from 'vuex'import Note from '@/models/NoteModel'import ToDo from "@/models/ToDoModel"import { useRefHistory } from '@vueuse/core'import { ref } from 'vue'const note: any = ref({  title: "",  todos: [] as ToDo[]})const { history, undo, redo, canUndo, canRedo, clear } = useRefHistory(note, {  deep: true})export default createStore({  state: {    currentNote: note as Note,    currentId: 0  },  mutations: {    // mutations    clearHistory() {      clear()    },    undoChanges() {      undo()    },    redoChanges() {      redo()    }  },  actions: {      },  getters: {    canUndo() {      return canUndo.value    },    canRedo() {      return canRedo.value    }  },  strict: true})

Создаем реактивную переменную с помощью ref, передаем ее в хук useRefHistory, в параметрах хука обозначаем deep: true, для вложенных объектов. С помощью деструктурирующего присваивания из useRefHistory получаем history, undo, redo, canUndo,canRedo и clear. Функции undo и redo, необходимо применять только в мутациях, чтобы Vuex не ругался. Свойства canUndo и canRedo можно передать через геттеры, которые потом повесить на атрибуты disabled в кнопках. clear необходима для очистки истории после окончания редактирования записей. Хук useManualRefHistory делает практически тоже самое, но сохранение в историю происходит только по вызову команды commit().


Я рассказал всего про 3 функции из большого арсенала инструментов VueUse для разработки на Vue 3. Для более глубокого изучения советую посетить сайт этой замечательной библиотеки. Документация все еще далека от совершенства, но она регулярно обновляется как и сама библиотека.

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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru