Евгений Колесников 1 vuosi sitten
vanhempi
sitoutus
6a8e43df9e
3 muutettua tiedostoa jossa 108 lisäystä ja 17 poistoa
  1. 107 17
      articles/web_17.md
  2. BIN
      img/web_024.png
  3. 1 0
      readme.md

+ 107 - 17
articles/web_17.md

@@ -1,34 +1,124 @@
 [К содержанию](../readme.md#введение-в-web-разработку)
 
-# Криптономикон-5: Работа со списком - Vue.js: практика
+# Управление состоянием (pinia)
 
-<!-- 31 мин -->
+## Что такое управление состоянием?​
 
-1. [#16 Криптономикон-5: Работа со списком - Vue.js: практика](https://www.youtube.com/watch?v=BNDo6MVbPn4)
+Технически каждый экземпляр компонента **Vue** уже "управляет" своим реактивным состоянием. Возьмём для примера простой компонент счетчика:
 
-    **Содержание урока:**
+```vue
+<script setup>
+import { ref } from 'vue'
 
-    - сохранение/восстановление тикеров в *LocalStorage* (с переподпиской при обновлении страницы)
-    - фильтрация
-    - пагинация
-    - watch
-    - url history (хранение фильтра и пагинатора)
+// состояние
+const count = ref(0)
 
-    **Материалы к изучению:**
+// действия
+function increment() {
+  count.value++
+}
+</script>
 
-    - [watch (наблюдатели)](https://v3.ru.vuejs.org/ru/guide/computed.html#%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B-%D0%BD%D0%B0%D0%B1%D0%BB%D1%8E%D0%B4%D0%B0%D1%82%D0%B5%D0%BB%D0%B8)
+<!-- представление -->
+<template>{{ count }}</template>
+```
 
-    - [исходный код урока](https://gitlab.com/vuejs-club/youtube-course/cryptonomicon/-/tree/lesson4)
+Это самостоятельный блок, состоящий из следующих частей:
 
 
-1. Продолжаем изучать вторую часть учебника [JavaScript (Разное)](https://learn.javascript.ru/ui-misc) 
+* **Состояние** - источник данных, который управляет нашим приложением;
+* **Представление** - декларативное отображение состояния;
+* **Действия** - возможные способы изменения состояния в ответ на пользовательский ввод из представления.
 
----
+Это простое представление концепции "одностороннего потока данных":
 
-## Задание
+![](../img/web_024.png)
 
-1. Пересмотреть видео [#16 Криптономикон-5: Работа со списком - Vue.js: практика](https://www.youtube.com/watch?v=BNDo6MVbPn4) и доработать свой код. 
+Однако эта простота начинает нарушаться, когда у нас есть **несколько компонентов, имеющих общее состояние**:
 
-1. Перечитать и осмыслить раздел "Разное" второй части часть [Учебника](https://learn.javascript.ru/ui-misc)
+1. Несколько представлений могут зависеть от одного и того же фрагмента состояния.
+1. Действиям из разных представлений может потребоваться мутировать один и тот же фрагмент состояния.
+
+В первом случае возможным обходным путем является "поднятие" общего состояния до общего компонента-предка, а затем передача его вниз в виде входных параметров. Однако это быстро становится утомительным в деревьях компонентов с глубокой иерархией, что приводит к другой проблеме, известной как **пробрасывание входных параметров (prop drilling)**.
+
+Во втором случае мы часто прибегаем к таким решениям, как обращение к прямым родительским и дочерним экземплярам через ссылки на элементы шаблона или попытка мутировать и синхронизировать несколько копий состояния через генерируемые события. Оба эти паттерна являются хрупкими и быстро приводят к сложно поддерживаемому коду.
+
+Более простым и понятным решением является извлечение общего состояния из компонентов и управление им в глобальном синглтоне. Таким образом, наше дерево компонентов превращается в большое "представление", и любой компонент может получить доступ к состоянию или вызвать действия, независимо от того, где он находится в дереве!
+
+**Pinia** - это библиотека для создания хранилища для Vue, которая позволяет вам совместно использовать состояние между компонентами/страницами.
+
+## Что такое хранилище?
+
+Хранилище (как, например, Pinia) - это сущность, которая содержит состояние и бизнес-логику, не привязанную к дереву компонентов. Другими словами, она содержит глобальное состояние. Это немного похоже на компонент, и у которого все могут читать и записывать данные. В нем есть три основных концепции: [состояние (state)](https://pinia-ru.netlify.app/core-concepts/state.html), [геттеры (getters)](https://pinia-ru.netlify.app/core-concepts/getters.html) и [действия (actions)](https://pinia-ru.netlify.app/core-concepts/actions.html), и можно с уверенностью предположить, что эти концепции эквивалентны `data`, `computed` и `methods` в компонентах (про эти концепции вы слышали в лекциях про **vue2**, во **vue3** их уже нет).
+
+## Начало работы с Pinia
+
+### Установка
+
+При создании SPA приложения вы должны были установить и pinia, но если не установили, то всегда можно добавить [вручную](https://pinia-ru.netlify.app/getting-started.html#instalation)
+
+## [Определение хранилища](https://pinia-ru.netlify.app/core-concepts/#defining-a-store)
+
+**Pinia** поддерживает два варианта синтаксиса: [option](https://pinia-ru.netlify.app/core-concepts/#option-stores) и [setup](https://pinia-ru.netlify.app/core-concepts/#setup-stores).
+
+Принципиальной разницы между ними нет, синтаксис аналогичен таким же наименованиям во **VUE**, поэтому далее мы будем использовать вариант **setup**.
+
+В "рыбе" нашего **SPA** приложения уже есть пример хранилища (`src/stores/counters.js`):
+
+```js
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+export const useCounterStore = defineStore('counter', () => {
+  const count = ref(0)
+  const doubleCount = computed(() => count.value * 2)
+  function increment() {
+    count.value++
+  }
+
+  return { count, doubleCount, increment }
+})
+```
+
+Как видите, используются уже знакомые вам концепции _реактивных переменных_ (_ref_), _вычисляемых переменных_ (_computed_) и методов (_function_).
+
+## [Использование хранилища](https://pinia-ru.netlify.app/core-concepts/#using-the-store)
+
+Для подключения хранилища к компоненту используется обычный импорт:
+
+```vue
+<script setup>
+import { useCounterStore } from 'src/stores/counter'
+
+// доступ к переменной `store` в любом месте компонента
+const store = useCounterStore()
+</script>
+```
+
+Для получения значений свойств хранилища или вызыва его методов используйте _store_ как обычный объект
+
+```js
+const value = store.count
+store.increment()
+```
+
+Но надо учитывать, что свойства этого объекта не реактивны.
+
+Чтобы извлечь свойства из хранилища, сохраняя их реактивность, можно использовать метод _storeToRefs()_. Он создаст **ref**-ссылки для каждого реактивного свойства. Это полезно, когда вы используете только состояние из хранилища, но не вызываете никакие действия. Обратите внимание, что вы также можете деструктурировать действия напрямую из хранилища, так как они также привязаны к самому хранилищу:
+
+```vue
+<script setup>
+import { useCounterStore } from '@/stores/counter'
+import { storeToRefs } from 'pinia'
+
+const store = useCounterStore()
+// `name` и `doubleCount` являются реактивными ref-ссылками
+// При этом также будут извлечены ref-ссылки на свойства, добавленные плагинами
+// но будет пропущено любое действие или нереактивное (не ref/reactive) свойство
+const { name, doubleCount } = storeToRefs(store)
+// действие increment может быть просто деструктурировано
+const { increment } = store
+</script>
+```
 
 [Назад](./web_16.md) | [Дальше](./web_18.md)

BIN
img/web_024.png


+ 1 - 0
readme.md

@@ -352,6 +352,7 @@ https://office-menu.ru/uroki-sql Уроки SQL
 1. [Vue.js: компоненты](./articles/web_14.md)
 1. [Vue.js: Нативные события](./articles/web_15.md)
 1. [Vue.js: Single-page application, маршрутизация](./articles/web_16.md)
+1. [Vue.js: Управление состоянием (pinia)](./articles/web_17.md)
 
 <!--