forked from vuejs/vuex
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from flaxflour/translation-ru-v4
docs(ru): add Vuex 4.x translation
- Loading branch information
Showing
23 changed files
with
12,930 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
# Действия | ||
|
||
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c6ggR3cG" target="_blank" rel="noopener noreferrer">Пройдите этот урок на Scrimba</a></div> | ||
|
||
Действия — похожи на мутации с несколькими отличиями: | ||
|
||
* Вместо того, чтобы напрямую менять состояние, действия инициируют мутации; | ||
* Действия могут использоваться для асинхронных операций. | ||
|
||
Зарегистрируем простое действие: | ||
|
||
```js | ||
const store = createStore({ | ||
state: { | ||
count: 0 | ||
}, | ||
mutations: { | ||
increment(state) { | ||
state.count++ | ||
} | ||
}, | ||
actions: { | ||
increment(context) { | ||
context.commit('increment') | ||
} | ||
} | ||
}) | ||
``` | ||
|
||
Обработчики действий получают объект контекста, содержащий те же методы и свойства, что и сам экземпляр хранилища, так что можно вызвать `context.commit` для инициирования мутации или обратиться к состоянию и геттерам через `context.state` и `context.getters`. Можно даже вызывать другие действия через `context.dispatch`. Позднее при рассмотрении [модулей](modules.md) будет видно, что этот контекст — не то же самое, что экземпляр хранилища. | ||
|
||
На практике для упрощения кода часто используется [деструктуризация аргументов](https://github.com/lukehoban/es6features#destructuring) из ES2015 (особенно при необходимости многократного вызова `commit`): | ||
|
||
```js | ||
actions: { | ||
increment ({ commit }) { | ||
commit('increment') | ||
} | ||
} | ||
``` | ||
|
||
## Диспетчеризация действий | ||
|
||
Действия запускаются методом `store.dispatch`: | ||
|
||
```js | ||
store.dispatch('increment') | ||
``` | ||
|
||
На первый взгляд может выглядеть глупо: если хочется увеличить значение count, почему бы просто не вызвать `store.commit('increment')` напрямую? Помните, что **мутации должны быть синхронными**. Для действий такого ограничения нет. Внутри действий можно выполнять **асинхронные** операции: | ||
|
||
```js | ||
actions: { | ||
incrementAsync ({ commit }) { | ||
setTimeout(() => { | ||
commit('increment') | ||
}, 1000) | ||
} | ||
} | ||
``` | ||
|
||
Действия поддерживают тот же формат для передачи нагрузки, а также объектный синтаксис: | ||
|
||
``` js | ||
// вызов с нагрузкой | ||
store.dispatch('incrementAsync', { | ||
amount: 10 | ||
}) | ||
|
||
// объектный синтаксис | ||
store.dispatch({ | ||
type: 'incrementAsync', | ||
amount: 10 | ||
}) | ||
``` | ||
|
||
Более приближённым к реальности примером действий будет формирование заказа на основе состояния корзины покупок. Логика такого действия включает в себя **вызов асинхронного API** и **инициализацию нескольких мутаций**: | ||
|
||
``` js | ||
actions: { | ||
checkout ({ commit, state }, products) { | ||
// сохраним находящиеся на данный момент в корзине товары | ||
const savedCartItems = [...state.cart.added] | ||
// инициируем запрос и «оптимистично» очистим корзину | ||
commit(types.CHECKOUT_REQUEST) | ||
// предположим, что API магазина позволяет передать коллбэки | ||
// для обработки успеха и неудачи при формировании заказа | ||
shop.buyProducts( | ||
products, | ||
// обработка успешного исхода | ||
() => commit(types.CHECKOUT_SUCCESS), | ||
// обработка неудачного исхода | ||
() => commit(types.CHECKOUT_FAILURE, savedCartItems) | ||
) | ||
} | ||
} | ||
``` | ||
|
||
Таким образом удаётся организовать поток асинхронных операций, записывая побочные эффекты действий в виде мутаций состояния. | ||
|
||
## Диспетчеризация действий в компонентах | ||
|
||
Диспетчеризировать действия в компонентах можно при помощи `this.$store.dispatch('xxx')` или используя вспомогательную функцию `mapActions`, создающую локальные псевдонимы для действий в виде методов компонента (требуется наличие корневого `$store`): | ||
|
||
``` js | ||
import { mapActions } from 'vuex' | ||
|
||
export default { | ||
// ... | ||
methods: { | ||
...mapActions([ | ||
'increment' // проксирует `this.increment()` в `this.$store.dispatch('increment')` | ||
|
||
// `mapActions` также поддерживают нагрузку (payloads): | ||
'incrementBy' // проксирует `this.incrementBy(amount)` в `this.$store.dispatch('incrementBy', amount)` | ||
]), | ||
...mapActions({ | ||
add: 'increment' // проксирует `this.add()` в `this.$store.dispatch('increment')` | ||
}) | ||
} | ||
} | ||
``` | ||
|
||
## Композиция действий | ||
|
||
Раз действия зачастую асинхронны, то как узнать, что действие уже завершилось? И, что важнее, как быть со связанными между собой действиями при организации более сложных асинхронных потоков? | ||
|
||
Первое, что нужно знать — `store.dispatch` может обрабатывать Promise, возвращаемый обработчиком действия, и также возвращает Promise: | ||
|
||
``` js | ||
actions: { | ||
actionA ({ commit }) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => { | ||
commit('someMutation') | ||
resolve() | ||
}, 1000) | ||
}) | ||
} | ||
} | ||
``` | ||
|
||
Теперь можно сделать так: | ||
|
||
```js | ||
store.dispatch('actionA').then(() => { | ||
// ... | ||
}) | ||
``` | ||
|
||
А в другом действии — так: | ||
|
||
```js | ||
actions: { | ||
// ... | ||
actionB ({ dispatch, commit }) { | ||
return dispatch('actionA').then(() => { | ||
commit('someOtherMutation') | ||
}) | ||
} | ||
} | ||
``` | ||
|
||
Наконец, если использовать [async / await](https://tc39.github.io/ecmascript-asyncawait/), то можно компоновать действия следующим образом: | ||
|
||
```js | ||
// предположим, что `getData()` и `getOtherData()` возвращают Promise | ||
|
||
actions: { | ||
async actionA ({ commit }) { | ||
commit('gotData', await getData()) | ||
}, | ||
async actionB ({ dispatch, commit }) { | ||
await dispatch('actionA') // дожидаемся завершения действия `actionA` | ||
commit('gotOtherData', await getOtherData()) | ||
} | ||
} | ||
``` | ||
|
||
> `store.dispatch` может вызывать несколько обработчиков действий в различных модулях одновременно. В этом случае возвращаемым значением будет Promise, разрешающийся после разрешения всех вызванных обработчиков. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Composition API | ||
|
||
Чтобы получить доступ к хранилищу в хуке `setup`, можно использовать функцию `useStore`. Это эквивалент получения `this.$store` внутри компонента с помощью Options API. | ||
|
||
```js | ||
import { useStore } from 'vuex' | ||
|
||
export default { | ||
setup () { | ||
const store = useStore() | ||
} | ||
} | ||
``` | ||
|
||
## Доступ к состоянию и геттерам | ||
|
||
Чтобы получить доступ к состоянию и геттерам, нужно создать `вычисляемые` ref-ссылки для сохранения реактивности. Это эквивалентно созданию вычисляемых свойств с помощью Options API. | ||
|
||
```js | ||
import { computed } from 'vue' | ||
import { useStore } from 'vuex' | ||
|
||
export default { | ||
setup () { | ||
const store = useStore() | ||
|
||
return { | ||
// доступ к состоянию в вычисляемой функции | ||
count: computed(() => store.state.count), | ||
|
||
// доступ к геттеру в вычисляемой функции | ||
double: computed(() => store.getters.double) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Доступ к мутациям и действиям | ||
|
||
При доступе к мутациям и действиям, можно просто указать методы `commit` и `dispatch` внутри `setup` хука. | ||
|
||
```js | ||
import { useStore } from 'vuex' | ||
|
||
export default { | ||
setup () { | ||
const store = useStore() | ||
|
||
return { | ||
// доступ к мутациям | ||
increment: () => store.commit('increment'), | ||
|
||
// доступ к действиям | ||
asyncIncrement: () => store.dispatch('asyncIncrement') | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Примеры | ||
|
||
Ознакомьтесь с [примером Composition API](https://github.com/vuejs/vuex/tree/4.0/examples/composition) чтобы увидеть пример приложения, использующих Vuex и Vue Composition API. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Работа с формами | ||
|
||
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cqKRgEC9" target="_blank" rel="noopener noreferrer">Пройдите этот урок на Scrimba</a></div> | ||
|
||
При использовании строгого режима Vuex может показаться неочевидным как использовать `v-model` с частью состояния Vuex: | ||
|
||
``` html | ||
<input v-model="obj.message"> | ||
``` | ||
|
||
Предположим, что `obj` — вычисляемое свойство, которое просто возвращает ссылку на объект из хранилища. В таком случае, `v-model` будет пытаться напрямую изменять значение `obj.message` при действиях пользователя. В строгом режиме такие изменения спровоцируют ошибку, поскольку они происходят вне обработчиков мутаций Vuex. | ||
|
||
Для работы с Vuex в такой ситуации, следует привязать значение к `<input>` и отслеживать его изменения по событию `input` или `change`: | ||
|
||
``` html | ||
<input :value="message" @input="updateMessage"> | ||
``` | ||
|
||
``` js | ||
// ... | ||
computed: { | ||
...mapState({ | ||
message: state => state.obj.message | ||
}) | ||
}, | ||
methods: { | ||
updateMessage (e) { | ||
this.$store.commit('updateMessage', e.target.value) | ||
} | ||
} | ||
``` | ||
|
||
А вот и обработчик мутаций: | ||
|
||
``` js | ||
// ... | ||
mutations: { | ||
updateMessage (state, message) { | ||
state.obj.message = message | ||
} | ||
} | ||
``` | ||
|
||
## Двунаправленные вычисляемые свойства | ||
|
||
Заметно, что получившаяся выше запись — куда многословнее, чем используемая в связке `v-model` с локальным состоянием, да и некоторые полезные возможности `v-model` таким образом упускаются. В качестве альтернативы можно предложить использование двунаправленного вычисляемого свойства с сеттером: | ||
|
||
``` html | ||
<input v-model="message"> | ||
``` | ||
|
||
``` js | ||
// ... | ||
computed: { | ||
message: { | ||
get () { | ||
return this.$store.state.obj.message | ||
}, | ||
set (value) { | ||
this.$store.commit('updateMessage', value) | ||
} | ||
} | ||
} | ||
``` |
Oops, something went wrong.