Vue сохранение данных в браузере
Уже изучили Vue 2 и хотите узнать, что нового во Vue 3? Посмотрите руководство по миграции!
Vue (произносится /vjuː/, примерно как view) — прогрессивный фреймворк для создания пользовательских интерфейсов. В отличие от фреймворков-монолитов, Vue создавался пригодным для постепенного внедрения. Его ядро в первую очередь решает задачи уровня представления (view), упрощая интеграцию с другими библиотеками и существующими проектами. С другой стороны, Vue полностью подходит и для разработки сложных одностраничных приложений (SPA, Single-Page Applications), если использовать его в комбинации с современными инструментами и дополнительными библиотеками
Если хотите узнать о Vue больше, прежде чем начать — посмотрите видео с рассказом об основных принципах работы на небольшом примере проекта.
Video by Vue Mastery. Watch Vue Mastery’s free Intro to Vue course.
В руководстве предполагаются знания HTML, CSS и JavaScript на среднем уровне. Для новичков во фронтенд-разработке сразу начинать изучение с фреймворка может быть не лучшей идеей — возвращайтесь, разобравшись с основами! Наличие опыта работы с другими фреймворками может помочь, но не является обязательным.
Самый простой способ попробовать Vue.js — пример Hello World
(opens new window) . Открывайте его в соседней вкладке и практикуйтесь, изменяя по ходу изучения руководства.
На странице установки перечислено несколько вариантов как устанавливать Vue. Примечание: начинающим программистам не рекомендуем стартовать с vue-cli , особенно если ещё не знакомы с инструментами сборки на основе Node.js.
В ядре Vue.js находится система, позволяющая декларативно отрисовывать данные в DOM с помощью простого синтаксиса шаблонов:
Вот и первое Vue-приложение! Хоть и выглядит как простая отрисовка строкового шаблона, но «под капотом» Vue выполнил немало работы. Данные и DOM теперь реактивно связаны. Как в этом убедиться? Посмотрите на пример ниже, где свойство counter увеличивается каждую секунду и увидите, как изменяется DOM:
Кроме интерполяции текста также можно связывать данные с атрибутами элементов:
Здесь повстречались с чем-то новым. Атрибут v-bind называется директивой. Директивы именуются с префикса v- , который обозначает, что это специальные атрибуты Vue, и, как уже можно догадаться, они добавляют особое реактивное поведение отрисованному DOM. В примере выше директива говорит «сохраняй значение title этого элемента актуальным при изменении свойства message в текущем активном экземпляре».
Чтобы позволить пользователям взаимодействовать с приложением, можно использовать директиву v-on для обработчиков событий, которые будут вызывать методы экземпляра:
Обратите внимание, в методе не трогаем DOM и обновляем только состояние приложения — всеми манипуляциями с DOM занимается Vue, а в коде фокусируемся на логике работы.
Vue также предоставляет директиву v-model , которая реализует двустороннюю привязку между элементом формы и состоянием приложения:
Управлять присутствием элемента в DOM тоже просто:
Пример выше демонстрирует возможность связывания данных не только с текстом и атрибутами, но и со структурой DOM. Кроме того, Vue имеет мощную систему анимаций, которая может автоматически применять эффекты переходов при добавлении, обновлении или удалении элементов.
В примере ниже можно изменять значение seen с true на false чтобы увидеть эффект:
Есть и некоторое количество других директив, каждая из которых обладает своей особой функциональностью. Например, директиву v-for можно использовать для отображения списка элементов, используя данные из массива:
Компонентная система является ещё одной важной концепцией во Vue, потому что это абстракция, которая позволяет создавать большие приложения, состоящие из небольших, автономных и часто переиспользуемых компонентов. Если задуматься, то почти любой тип интерфейса приложения можно абстрактно представить в виде дерева компонентов:
Компонент во Vue — по сути экземпляр с предустановленными опциями. Его регистрация также проста: нужно создать объект компонента, как это уже делали с объектом app , и указать его в родительской опции components :
После этого можно использовать его в шаблоне другого компонента:
Пока что во всех элементах списка будет один и тот же текст, что не очень-то интересно. Должна быть возможность передавать данные в дочерние компоненты из родительской области видимости. Доработаем компонент, чтобы он принимал входной параметр:
Теперь можно передавать свой текст для каждого из компонентов с помощью v-bind :
Конечно, это несколько надуманный пример, но приложение удалось разделить на два блока поменьше. Дочерний компонент достаточно хорошо изолирован от родительского интерфейсом входных параметров. Теперь можно дорабатывать компонент , изменяя его шаблон и логику и не затрагивать работу родительского приложения.
В больших приложениях разделение на компоненты становится жизненной необходимостью для сохранения управляемости разработки. Гораздо подробнее с компонентами продолжим разбираться далее в руководстве, но и сейчас можно взглянуть на (вымышленный) пример того, как может выглядеть шаблон приложения, использующего компоненты:
Можно заметить, что компоненты Vue похожи на пользовательские элементы, являющиеся частью спецификации веб-компонентов
(opens new window) . Некоторые элементы дизайна компонентов Vue (например, API слотов) действительно разрабатывались под влиянием этой спецификации ещё до того, как она была реализована в браузерах.
Но главное отличие в том, что компонентная модель Vue разработана как часть целостного фреймворка, предоставляющего множество дополнительных возможностей, необходимых при создании нетривиальных приложений, например, реактивный шаблонизатор и управление состоянием — оба этих аспекта не покрываются спецификацией.
Vue также предоставляет отличную поддержку как для использования, так и для создания пользовательских элементов. Более подробную информацию можно найти в разделе Vue и веб-компоненты.
Пока что лишь вкратце познакомились с основными функциями ядра Vue.js — в следующих разделах руководства будем разбирать подробнее эти и другие интересные возможности, поэтому не забудьте прочитать его целиком!
Если вы разрабатываете приложения на Vue, тогда вам нужно следить за утечками памяти. Эта проблема особенно важна в одностраничных приложениях (SPA), потому что идея использования SPA состоит в отсутствии пользователям необходимости обновлять страницы браузера, поэтому задачей JavaScript приложения также будет и очистка в компонентах от лишнего.
Утечки памяти в приложениях Vue обычно не исходят от самого Vue, скорее они могут происходить при интеграции других библиотек в приложение.
Простой пример
В этом примере показана утечка памяти, вызванная использованием библиотеки Choices.js внутри компонента Vue без очистки ресурсов должным образом. Далее мы покажем как удалять остающееся после Choices.js и избежать утечки памяти.
В примере ниже, мы загружаем в select большое число вариантов выбора, а также используем кнопку для отображения/скрытия с помощью директивы v-if, чтобы добавлять и удалять список из виртуального DOM. Проблема в этом примере заключается в том, что директива v-if удаляет родительский элемент из DOM, но не выполняет дополнительную очистку DOM от частей, созданных Choices.js, что и вызывает утечку памяти.
Чтобы увидеть эту утечку памяти в действии, откройте этот пример на CodePen с помощью Chrome и затем откройте Диспетчер задач Chrome. Чтобы открыть на Mac, выберите в верхнем меню > Окно > Диспетчер задач или на Windows с помощью сочетания клавиш Shift+Esc. Теперь, нажимайте кнопку показать/скрыть около 50 раз. Вы сможете увидеть увеличение использованной памяти в Диспетчере задач Chrome, которая не будет освобождена.
Исправление утечки памяти
В примере выше, мы можем использовать наш метод hide() для выполнения очистки и устранения утечки памяти перед удалением select из DOM. Для этого мы будем хранить свойство в нашем экземпляре Vue и будем использовать API плагина Choices в методе destroy() для выполнения необходимых операций очистки.
Проверьте использование памяти в обновлённом примере на CodePen.
Подробнее о значимости
Управлением памятью и тестированием производительности часто легко можно пренебречь в спешке выпустить готовый продукт, но, тем не менее, сохранение небольшого количества используемой памяти по-прежнему важно для пользовательского опыта использования в целом.
Определите типы устройств, которые ваши пользователи могут использовать и какой сценарий работы с приложением может быть. Могут ли они использовать ноутбуки или мобильные устройства с небольшим количеством памяти? Будут ли ваши пользователи обычно совершать много переходов между страницами приложения? Если ответы на эти вопросы — «да», тогда хорошие практики управления памятью могут помочь избежать вам наихудшего сценария сбоя браузера пользователя. Даже если ни один ответ на вопрос не будет «да», вы по-прежнему можете ухудшить производительность вашего приложения при длительном использовании, если не будете осторожны.
Пример из жизни
В примере выше, мы использовали директиву v-if чтобы проиллюстрировать утечку памяти, но более распространённый сценарий из жизни возникает при использовании vue-router для маршрутизации по компонентам в одностраничном приложении (SPA).
Также, как и директива v-if , vue-router удаляет элементы из виртуального DOM и заменяет их новыми элементами при навигации пользователя по вашему приложению. Хук жизненного цикла beforeDestroy() — хорошее место для решения подобной проблемы в приложениях на основе vue-router .
Мы могли бы переместить нашу очистку в хук beforeDestroy() следующим образом:
Альтернативы
Мы обсудили управление памятью при удалении элементов, но что, если вы намеренно хотите сохранять состояние и сохранить элементы в памяти? В этом случае вы можете использовать встроенный компонент keep-alive.
Когда вы оборачиваете компонент с помощью keep-alive , его состояние будет сохранено, и следовательно, останется в памяти.
Эта техника может быть полезна для улучшения пользовательского опыта работы с приложением. Например, представьте, что пользователь начинает вводить комментарий в текстовое поле и затем решает перейти на другую страницу. Если пользователь вернётся обратно, то его комментарий останется сохранён в поле.
С тех пор, как начнёте использовать keep-alive, у вас появится доступ к двум дополнительным хукам жизненного цикла: activated и deactivated . Если вы хотите выполнить очистку или изменить данные при удалении компонента с keep-alive, вы можете сделать это в хуке deactivated .
Подытожим
Vue позволяет легко разрабатывать потрясающие реактивные JavaScript-приложения, но вам всё равно нужно уделять внимание утечкам памяти. Эти утечки обычно происходят при использовании дополнительных сторонних библиотек, которые манипулируют DOM вне Vue. Не забудьте проверить ваше приложение на утечки памяти и предпринять соответствующие шаги для добавления необходимых очисток в компонентах, где это необходимо.
В этом рецепте мы сфокусируемся на Local Storage (далее — локальное хранилище), простейшем механизме хранения. Локальное хранилище использует систему ключ-значение для хранения данных. Это ограничивает нас хранением только простых значений, но сложные структуры данных возможно сохранять, если вы готовы сериализовывать их в JSON и обратно. Локальное хранилище подходит для небольших наборов данных, например, настроек пользователя или данных формы. Для больших объёмов данных, где требуются комплексные требования к хранению, лучше использовать IndexedDB.
Давайте начнём с простого примера в виде формы:
Этот пример имеет одно поле ввода, привязанное к свойству данных name в экземпляре Vue:
Обратите внимание на фрагменты mounted и watch . Мы используем mounted для управления загрузкой значения из localStorage. Для управления записью данных в базу, мы следим за значением name и немедленно записываем изменения.
Вы можете запустить этот пример самостоятельно здесь:
Введите что-нибудь в форму и затем обновите эту страницу. Вы заметите, что введённое вами ранее значение будет показано автоматически. Не забывайте, что ваш браузер предоставляет замечательные инструменты разработчика для просмотра хранилища на стороне клиента. Ниже пример в Firefox:
И вот пример в Chrome:
И наконец пример в Microsoft Edge. Обратите внимание, что вы можете найти сохранённые значения приложения на вкладке «Отладчик».
Небольшая заметка: инструменты разработчика также предоставляют возможность удалять значения из хранилища. Это может быть очень полезным при тестировании.
Немедленная запись значения может быть нецелесообразной. Давайте рассмотрим чуть более сложный пример. Во-первых, обновим форму.
У нас есть 2 поля (опять-таки связанные с экземпляром Vue), но теперь добавилась и кнопка, запускающая метод persist . Давайте посмотрим на код JavaScript.
Как и раньше, используем mounted для получения сохранённых данных, если такие были. На этот раз, однако, данные сохраняются только при нажатии кнопки. Мы также можем сделать любые проверки или преобразования перед сохранением значения. Вы также можете сохранить дату последнего обновления данных. С такими метаданными, метод mounted может проверять, следует ли сохранять значения снова или нет. Вы можете попробовать эту версию ниже.
Работа со сложными значениями
Локальное хранилище работает только с простыми значениями. Для хранения более комплексных значений (объектов или массивов) вам необходимо будет самостоятельно преобразовывать их в JSON и обратно. Ниже представлен пример сохранения массива кошек.
Это приложение состоит из простого списка сверху (с кнопкой для удаления кота) и небольшой формы внизу для добавления нового кота. Посмотрим на код JavaScript.
В этом приложении мы будем использовать Local Storage API вместо «прямого» доступа. Оба варианта работают, однако метод API в целом предпочтительнее. В хуке mounted мы получаем JSON-значение и преобразуем в объект. Если что-то пошло не так, мы предполагаем, что данные повреждены и удаляем их. (Помните, если ваше приложение использует хранилище на стороне клиента, пользователь в любое время имеет доступ к нему и может изменить на своё усмотрение).
Теперь у нас есть три метода для управления списком котов. Как addCat , так и removeCat обновляют данные экземпляра Vue в this.cats . Затем они вызывают метод saveCats , который занимается сериализацией и сохранением данных. Вы можете попробовать эту версию ниже.
Альтернативные варианты
В то время как Local Storage API относительно прост, в нём отсутствуют некоторые базовые возможности, которые будут полезны во многих приложениях. Следующие плагины оборачивают доступ к локальному хранилищу и упрощают его, а также добавляют такую функциональность, как, например, значения по умолчанию.
Итоги
Хотя браузер никогда не заменит системы хранения на сервере, наличие различных способов кэширования данных локально может дать огромный прирост производительности вашему приложению, и работа с ними во Vue.js делает его ещё более мощным.
In this cookbook entry we’ll focus on Local Storage, the simplest of the storage mechanisms. Local Storage uses a key/value system for storing data. It is limited to storing only simple values but complex data can be stored if you are willing to encode and decode the values with JSON. In general, Local Storage is appropriate for smaller sets of data you would want to persist, things like user preferences or form data. Larger data with more complex storage needs would be better stored typically in IndexedDB.
Let’s begin with a simple form based example:
This example has one form field bound to a Vue value called name . Here’s the JavaScript:
Focus on the mounted and watch parts. We use mounted to handle loading the value from localStorage. To handle writing the data base, we watch the name value and on change, immediately write it.
Type something in the form and then reload this page. You’ll note that the value you typed previously will show up automatically. Don’t forget that your browser provides excellent developer tools for inspecting client-side storage. Here’s an example in Firefox:
And here it is in Chrome:
And then finally, an example in Microsoft Edge. Note that you can find application storage values under the Debugger tab.
As a quick aside, these dev tools also offer you a way to remove storage values. This can be very useful when testing.
Immediately writing the value may not be advisable. Let’s consider a slightly more advanced example. First, the updated form.
Now we’ve got two fields (again, bound to a Vue instance) but now there is the addition of a button that runs a persist method. Let’s look at the JavaScript.
As before, mounted is used to load persisted data, if it exists. This time, though, data is only persisted when the button is clicked. We could also do any validations or transformations here before storing the value. You could also store a date representing when the values were stored. With that metadata, the mounted method could make a logical call on whether or not to store the values again. You can try this version below.
Working with Complex Values
As mentioned above, Local Storage only works with simple values. To store more complex values, like objects or arrays, you must serialize and deserialize the values with JSON. Here is a more advanced example that persists an array of cats (the best kind of array possible).
This “app” consists of a simple list on top (with a button to remove a cat) and a small form at the bottom to add a new cat. Now let’s look at the JavaScript.
In this application, we’ve switched to use the Local Storage APIs versus “direct” access. Both work but the API method is generally preferred. mounted now has to grab the value and parse the JSON value. If anything goes wrong here we assume the data is corrupt and delete it. (Remember, any time your web application uses client-side storage, the user has access to it and can modify it at will.)
We have three methods now to handle working with cats. Both addCat and removeCat handle updating the “live” Vue data stored in this.cats . They then run saveCats which handles serializing and persisting the data. You can play with this version below:
Alternative Patterns
While the Local Storage API is relatively simple, it is missing some basic features that would be useful in many applications. The following plugins wrap Local Storage access and make it easier to use, while also adding functionality like default values.
Wrapping Up
While the browser will never replace a server persistence system, having multiple ways to cache data locally can be a huge performance boost for your application, and working with it in Vue.js makes it even more powerful.
Caught a mistake or want to contribute to the documentation? Edit this on GitHub! Deployed on Netlify .
Один из простых вариантов для сохранения состояния — использовать localStorage в браузере. Рассмотрим пример:
В этом компоненте с состоянием имеется count . Теперь предположим, что нам надо при перезагрузке страницы сохранить значение этого счетчика count . Для этого просто задействуем localStorage :
Теперь при задействовании localStorage в компоненте с состоянием значение этого состояния сохраняется, когда вызывается метод setState .
Это простой подход для сохранения состояния в классовых компонентах. Посмотрим, как добиться того же в функциональном компоненте.
Первым делом преобразуем компонент, основанный на классах, в функциональный компонент:
A теперь посмотрим, как при добавлении localStorage в функциональный компонент с состоянием добиться сохранения этого состояния:
В случае с функциональным компонентом применен несколько иной подход. Здесь использован хук useEffect , и сделано это для:
- Отслеживания изменений и обновления LocalStorage .
- Получения сохраненного значения из LocalStorage при инициализации.
Но при сохранении состояния в localStorage на уровне компонента возникает одна проблема. И связана она с наличием нескольких экземпляров одного и того же компонента. Это приводит к неожиданному поведению, так как в localStorage создаются повторяющиеся ключи.
У этой проблемы два решения:
- Передать идентификатор в повторно используемый компонент и задействовать его для хранения значения в localStorage .
- Или сохранять состояние на более высоком уровне.
Для сохранения состояния приложения в localStorage будем использовать Redux.
Здесь при использовании localStorage с Redux мы подписываемся на обновления хранилища и сохраняем это в localStorage . А при инициализации приложения передаем исходное состояние из localStorage .
Обратите внимание: здесь пригодится популярная библиотека Redux Persist.
А сохранять и инициализировать persistStore нам помогает persistReducer из Redux Persist.
Наконец добрались до самого очевидного варианта — использования параметров URL для сохранения состояния. А этот подход годится, в случае если данные предельно простые и со значениями-примитивами. Это обусловлено ограничениями по длине URL.
Если приглядеться к этому коду, то мы заметим, что он добавляет состояние в историю браузера. Поэтому при инициализации компонента мы наследуем исходные значения параметров URL.
Для сохранения состояния приложения на React используются localStorage и параметры URL.
В простой ситуации вполне сгодятся параметры URL. Если данные немного сложнее, стоит отдать предпочтение сохранению состояния в localStorage . В случае с localStorage решаем, где сохранять состояние: на уровне компонентов или на уровне приложений.
Чтобы упростить себе задачу и не заниматься сохранением и восстановлением состояния приложения вручную, задействуем библиотеки типа Redux Persist.
Какой бы вариант вы не выбрали, важно также сохранять контроль над изменениями состояния. Ведь после того, как состояние будет установлено, у некоторых пользователей приложение не сможет продолжать работу, если в более новой версии вы измените код, связанный с этим состоянием.
Читайте также: