Showing preview only (563K chars total). Download the full file or copy to clipboard to get everything.
Repository: vuejs/vuex
Branch: main
Commit: bd907467b839
Files: 222
Total size: 512.2 KB
Directory structure:
gitextract_cty0x9ut/
├── .babelrc
├── .eslintrc.json
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.yml
│ ├── ISSUE_TEMPLATE.md
│ ├── commit-convention.md
│ ├── contributing.md
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs/
│ ├── .vitepress/
│ │ ├── config.js
│ │ ├── styles/
│ │ │ └── styles.css
│ │ └── theme/
│ │ └── index.js
│ ├── api/
│ │ └── index.md
│ ├── guide/
│ │ ├── actions.md
│ │ ├── composition-api.md
│ │ ├── forms.md
│ │ ├── getters.md
│ │ ├── hot-reload.md
│ │ ├── index.md
│ │ ├── migrating-to-4-0-from-3-x.md
│ │ ├── modules.md
│ │ ├── mutations.md
│ │ ├── plugins.md
│ │ ├── state.md
│ │ ├── strict.md
│ │ ├── structure.md
│ │ ├── testing.md
│ │ └── typescript-support.md
│ ├── index.md
│ ├── installation.md
│ ├── ja/
│ │ ├── api/
│ │ │ └── index.md
│ │ ├── guide/
│ │ │ ├── actions.md
│ │ │ ├── composition-api.md
│ │ │ ├── forms.md
│ │ │ ├── getters.md
│ │ │ ├── hot-reload.md
│ │ │ ├── index.md
│ │ │ ├── migrating-to-4-0-from-3-x.md
│ │ │ ├── modules.md
│ │ │ ├── mutations.md
│ │ │ ├── plugins.md
│ │ │ ├── state.md
│ │ │ ├── strict.md
│ │ │ ├── structure.md
│ │ │ ├── testing.md
│ │ │ └── typescript-support.md
│ │ ├── index.md
│ │ └── installation.md
│ ├── ptbr/
│ │ ├── api/
│ │ │ └── index.md
│ │ ├── guide/
│ │ │ ├── actions.md
│ │ │ ├── composition-api.md
│ │ │ ├── forms.md
│ │ │ ├── getters.md
│ │ │ ├── hot-reload.md
│ │ │ ├── index.md
│ │ │ ├── migrating-to-4-0-from-3-x.md
│ │ │ ├── modules.md
│ │ │ ├── mutations.md
│ │ │ ├── plugins.md
│ │ │ ├── state.md
│ │ │ ├── strict.md
│ │ │ ├── structure.md
│ │ │ ├── testing.md
│ │ │ └── typescript-support.md
│ │ ├── index.md
│ │ └── installation.md
│ ├── public/
│ │ └── _redirects
│ └── zh/
│ ├── api/
│ │ └── index.md
│ ├── guide/
│ │ ├── actions.md
│ │ ├── composition-api.md
│ │ ├── forms.md
│ │ ├── getters.md
│ │ ├── hot-reload.md
│ │ ├── index.md
│ │ ├── migrating-to-4-0-from-3-x.md
│ │ ├── modules.md
│ │ ├── mutations.md
│ │ ├── plugins.md
│ │ ├── state.md
│ │ ├── strict.md
│ │ ├── structure.md
│ │ ├── testing.md
│ │ └── typescript-support.md
│ ├── index.md
│ └── installation.md
├── examples/
│ ├── classic/
│ │ ├── chat/
│ │ │ ├── api/
│ │ │ │ ├── index.js
│ │ │ │ └── mock-data.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── Message.vue
│ │ │ │ ├── MessageSection.vue
│ │ │ │ ├── Thread.vue
│ │ │ │ └── ThreadSection.vue
│ │ │ ├── css/
│ │ │ │ └── chat.css
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── counter/
│ │ │ ├── Counter.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store.js
│ │ ├── counter-hot/
│ │ │ ├── CounterControls.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── shopping-cart/
│ │ │ ├── api/
│ │ │ │ └── shop.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── ProductList.vue
│ │ │ │ └── ShoppingCart.vue
│ │ │ ├── currency.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── index.js
│ │ │ └── modules/
│ │ │ ├── cart.js
│ │ │ ├── nested.js
│ │ │ └── products.js
│ │ └── todomvc/
│ │ ├── app.js
│ │ ├── components/
│ │ │ ├── App.vue
│ │ │ └── TodoItem.vue
│ │ ├── index.html
│ │ └── store/
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── plugins.js
│ ├── composition/
│ │ ├── chat/
│ │ │ ├── api/
│ │ │ │ ├── index.js
│ │ │ │ └── mock-data.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── Message.vue
│ │ │ │ ├── MessageSection.vue
│ │ │ │ ├── Thread.vue
│ │ │ │ └── ThreadSection.vue
│ │ │ ├── css/
│ │ │ │ └── chat.css
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── counter/
│ │ │ ├── Counter.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store.js
│ │ ├── counter-hot/
│ │ │ ├── CounterControls.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── shopping-cart/
│ │ │ ├── api/
│ │ │ │ └── shop.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── ProductList.vue
│ │ │ │ └── ShoppingCart.vue
│ │ │ ├── currency.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── index.js
│ │ │ └── modules/
│ │ │ ├── cart.js
│ │ │ └── products.js
│ │ └── todomvc/
│ │ ├── app.js
│ │ ├── components/
│ │ │ ├── App.vue
│ │ │ └── TodoItem.vue
│ │ ├── index.html
│ │ └── store/
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── plugins.js
│ ├── global.css
│ ├── index.html
│ ├── server.js
│ └── webpack.config.js
├── jest.config.js
├── package.json
├── rollup.config.js
├── scripts/
│ ├── build.js
│ └── release.js
├── src/
│ ├── helpers.js
│ ├── index.cjs.js
│ ├── index.js
│ ├── index.mjs
│ ├── injectKey.js
│ ├── module/
│ │ ├── module-collection.js
│ │ └── module.js
│ ├── plugins/
│ │ ├── devtool.js
│ │ └── logger.js
│ ├── store-util.js
│ ├── store.js
│ └── util.js
├── test/
│ ├── .eslintrc.json
│ ├── e2e/
│ │ ├── cart.spec.js
│ │ ├── chat.spec.js
│ │ ├── counter.spec.js
│ │ └── todomvc.spec.js
│ ├── esm/
│ │ ├── esm-import.mjs
│ │ └── esm-test.js
│ ├── helpers.js
│ ├── setup.js
│ └── unit/
│ ├── helpers.spec.js
│ ├── hot-reload.spec.js
│ ├── module/
│ │ ├── module-collection.spec.js
│ │ └── module.spec.js
│ ├── modules.spec.js
│ ├── store.spec.js
│ └── util.spec.js
└── types/
├── README.md
├── helpers.d.ts
├── index.d.ts
├── logger.d.ts
├── test/
│ ├── helpers.ts
│ ├── index.ts
│ ├── tsconfig.json
│ └── vue.ts
├── tsconfig.json
└── vue.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": [
["@babel/preset-env", {
"exclude": [
"transform-regenerator"
]
}]
]
}
================================================
FILE: .eslintrc.json
================================================
{
"root": true,
"extends": [
"plugin:vue-libs/recommended"
],
"globals": {
"__DEV__": true,
"__VUE_PROD_DEVTOOLS__": true
}
}
================================================
FILE: .github/FUNDING.yml
================================================
github: [yyx990803, kiaking, ktsn]
open_collective: vuejs
patreon: evanyou
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: "\U0001F41E Bug report"
description: Create a report to help us improve
labels: ['bug: pending triage']
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please note that Vuex is now in maintenance mode and we will only prioritize critical issues.
Consider checking out [Pinia](https://pinia.vuejs.org/) for a more type-friendly and actively
maintained alternative.
- type: input
id: version
attributes:
label: Version
description: What version of Vuex is used in your project?
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
placeholder: Bug description
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Steps to reproduce the behavior.
placeholder: Reproduction
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
placeholder: Expected behavior
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Add any other context or screenshots about the bug report here.
- type: checkboxes
id: checkboxes
attributes:
label: Validations
description: Before submitting the issue, please make sure you do the following
options:
- label: Follow our [Code of Conduct](https://vuejs.org/about/coc.html)
required: true
- label: Read the [docs](https://vuex.vuejs.org/).
required: true
- label: Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
required: true
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
IMPORTANT: Please use the following link to create a new issue:
https://new-issue.vuejs.org/?repo=vuejs/vuex
If your issue was not created using the app above, it will be closed immediately.
-->
================================================
FILE: .github/commit-convention.md
================================================
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
#### TL;DR:
Messages must be matched by the following regex:
``` js
/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,50}/
```
#### Examples
Appears under "Features" header, `store` subheader:
```
feat(store): add 'watch' option
```
Appears under "Bug Fixes" header, `module` subheader, with a link to issue #28:
```
fix(module): handle state overwrite
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf: improve store getters performance by removing 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(store): add 'watch' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying the place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...
### Subject
The subject contains a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
================================================
FILE: .github/contributing.md
================================================
# Vuex Contributing Guide
Hi! We're really excited that you are interested in contributing to Vuex. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:
- [Code of Conduct](https://github.com/vuejs/vue/blob/dev/.github/CODE_OF_CONDUCT.md)
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
- [Pull Request Guidelines](#pull-request-guidelines)
## Issue Reporting Guidelines
- Always use [https://new-issue.vuejs.org/](https://new-issue.vuejs.org/) to create new issues.
## Pull Request Guidelines
- The `master` branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. **Do not submit PRs against the `master` branch.**
- Checkout a topic branch from the relevant branch, e.g. `dev`, and merge back against that branch.
- Work in the `src` folder and **DO NOT** checkin `dist` in the commits.
- If adding a new feature:
- Add accompanying test case.
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- If fixing bug:
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update state re-evaluation (fix #3899)`.
- Provide a detailed description of the bug in the PR. Live demo preferred.
- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.
- Make sure tests pass!
- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated.
================================================
FILE: .github/workflows/ci.yml
================================================
name: 'ci'
on:
push:
branches:
- '**'
pull_request:
branches:
- main
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set node version to 16
uses: actions/setup-node@v2
with:
node-version: 16
- name: Install deps
uses: bahmutov/npm-install@v1
- name: Run tests
run: npm test
================================================
FILE: .gitignore
================================================
/dist
/coverage
/docs/.vitepress/dist
/test/e2e/reports
/test/e2e/screenshots
*.log
.DS_Store
node_modules
================================================
FILE: CHANGELOG.md
================================================
# [4.1.0](https://github.com/vuejs/vuex/compare/v4.0.2...v4.1.0) (2022-10-14)
### Vue Core Version Requirement Change
**This release contains an important fix ([#1883](https://github.com/vuejs/vuex/pull/1883)) that relies on the `effectScope` API from Vue core, which is only available in Vue 3.2+.**
### Bug Fixes
* **build:** node deprecated warning in export module ([#2048](https://github.com/vuejs/vuex/issues/2048)) ([397e9fb](https://github.com/vuejs/vuex/commit/397e9fba45c8b4ec0c4a33d2578e34829bd348d7))
* getters being destroyed on component destroy ([#1878](https://github.com/vuejs/vuex/issues/1878)) ([#1883](https://github.com/vuejs/vuex/issues/1883)) ([b2f851f](https://github.com/vuejs/vuex/commit/b2f851f427aa872d1e4f5a4774e07c4c69562789))
## [4.0.2](https://github.com/vuejs/vuex/compare/v4.0.1...v4.0.2) (2021-06-17)
### Bug Fixes
* **devtools:** fix no getters displayed on root module + better getters inspector ([#1986](https://github.com/vuejs/vuex/issues/1986)) ([bc20295](https://github.com/vuejs/vuex/commit/bc20295331eb2bee40d6ae779d1ada31c542604c))
* **build:** cjs build failing due to `__VUE_PROD_DEVTOOLS__` defined ([#1991](https://github.com/vuejs/vuex/issues/1991)) ([#1992](https://github.com/vuejs/vuex/issues/1992)) ([7151622](https://github.com/vuejs/vuex/commit/7151622d646968686546f1c4c80f7575c9b99176))
## [4.0.1](https://github.com/vuejs/vuex/compare/v4.0.0...v4.0.1) (2021-05-24)
### Features
* dx: add devtools integration ([#1949](https://github.com/vuejs/vuex/pull/1949))
# [4.0.0](https://github.com/vuejs/vuex/compare/v4.0.0-rc.2...v4.0.0) (2021-02-02)
This is the official Vuex 4 release.
The focus for Vuex 4 is compatibility. Vuex 4 supports Vue 3, and it provides the exact same API as Vuex 3, so users can reuse their existing Vuex code with Vue 3.
There are a few breaking changes described in a later section, so please check them out.
You can find basic usage with both Option and Composition API in the `example` directory.
It's still released under `next` tag in NPM package as same as Vue 3. We're planning to remove `next` tag once Vue 3 is ready to remove it.
There have been a lot of contribution to make Vuex 4 stable. Thank you all for your very much appreciated help. It wouldn't have been possible without this wonderful Vue community!
## Documentation
To check out docs, visit [next.vuex.vuejs.org](https://next.vuex.vuejs.org/).
## Breaking changes
### Installation process has changed
To align with the new Vue 3 initialization process, the installation process of Vuex has changed.
To create a new store instance, users are now encouraged to use the newly introduced `createStore` function.
```js
import { createStore } from 'vuex'
export const store = createStore({
state() {
return {
count: 1
}
}
})
```
> Whilst this is not technically a breaking change, you may still use the `new Store(...)` syntax, we recommend this approach to align with Vue 3 and Vue Router Next.
To install Vuex to a Vue instance, pass the store instance instead of Vuex.
```js
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.mount('#app')
```
### Bundles are now aligned with Vue 3
The following bundles are generated to align with Vue 3 bundles:
- `vuex.global(.prod).js`
- For direct use with `<script src="...">` in the browser. Exposes the Vuex global.
- Global build is built as IIFE, and not UMD, and is only meant for direct use with `<script src="...">`.
- Contains hard-coded prod/dev branches and the prod build is pre-minified. Use the `.prod.js` files for production.
- `vuex.esm-browser(.prod).js`
- For use with native ES module imports (including module supporting browsers via `<script type="module">`.
- `vuex.esm-bundler.js`
- For use with bundlers such as `webpack`, `rollup` and `parcel`.
- Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).
- Does not ship minified builds (to be done together with the rest of the code after bundling).
- `vuex.cjs.js`
- For use in Node.js server-side rendering with `require()`.
### Typings for `ComponentCustomProperties`
Vuex 4 removes its global typings for `this.$store` within Vue Component to solve [issue #994](https://github.com/vuejs/vuex/issues/994). When used with TypeScript, you must declare your own module augmentation.
Place the following code in your project to allow `this.$store` to be typed correctly:
```ts
// vuex-shim.d.ts
import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'
declare module '@vue/runtime-core' {
// Declare your own store states.
interface State {
count: number
}
interface ComponentCustomProperties {
$store: Store<State>
}
}
```
### `createLogger` function is exported from the core module
In Vuex 3, `createLogger` function was exported from `vuex/dist/logger` but it's now included in the core package. You should import the function directly from `vuex` package.
```js
import { createLogger } from 'vuex'
```
### Bug Fixes Included Since 4.0.0-rc.2
* export missing `storeKey` ([4ab2947](https://github.com/vuejs/vuex/commit/4ab294793a2c20ea6040f01f316618682df61fff))
* fix tree shaking notworking in webpack bundle ([#1906](https://github.com/vuejs/vuex/issues/1906)) ([#1907](https://github.com/vuejs/vuex/issues/1907)) ([aeddf7a](https://github.com/vuejs/vuex/commit/aeddf7a7c618eda7f316f8a6ace8d21eb96c29ff))
# [4.0.0-rc.2](https://github.com/vuejs/vuex/compare/v4.0.0-rc.1...v4.0.0-rc.2) (2020-11-25)
### Bug Fixes
* fix getters stop working when component is destroyed ([#1884](https://github.com/vuejs/vuex/issues/1884)) ([c3a695e](https://github.com/vuejs/vuex/commit/c3a695e10682ab1b7288e72669861c9ca959df76))
* stop throwing an error on `hasModule` when parent does not exists ([#1850](https://github.com/vuejs/vuex/issues/1850)) ([f76d72d](https://github.com/vuejs/vuex/commit/f76d72d6c1f7cd30de9d459e23c371890c56f463))
### Features
* **build:** enable named esm module import on node.js >= 14 ([4f4a909](https://github.com/vuejs/vuex/commit/4f4a9096b46aa61580c32371adb19445157ba80c))
# [4.0.0-rc.1](https://github.com/vuejs/vuex/compare/v4.0.0-beta.4...v4.0.0-rc.1) (2020-10-30)
### Bug Fixes
* fix getters getting re-evaluated on every access ([#1823](https://github.com/vuejs/vuex/issues/1823)) ([#1860](https://github.com/vuejs/vuex/issues/1860)) ([0006765](https://github.com/vuejs/vuex/commit/0006765ca3c5641ef732bad9df58e01f05c6f19c))
* **types:** add lost argument of useStore ([#1803](https://github.com/vuejs/vuex/issues/1803)) ([657afe3](https://github.com/vuejs/vuex/commit/657afe3db42c8d1d721216955fc2be3132e9fe6c))
### Features
* **types:** adding logger type for logger plugin ([#1853](https://github.com/vuejs/vuex/issues/1853)) ([cb3198d](https://github.com/vuejs/vuex/commit/cb3198d5998bdb11ef05dfa5ef98d5c5fa873089))
## [3.5.1](https://github.com/vuejs/vuex/compare/v4.0.0-beta.3...v3.5.1) (2020-06-29)
# [4.0.0-beta.4](https://github.com/vuejs/vuex/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2020-06-29)
### Bug Fixes
* **types:** add missing `logger.d.ts` file to the package ([#1789](https://github.com/vuejs/vuex/issues/1789)) ([a477334](https://github.com/vuejs/vuex/commit/a477334b909913f6a92bdbedcf4a3016a62eab7a))
* warn when unregistering non existing module ([#1786](https://github.com/vuejs/vuex/issues/1786)) ([7cec79d](https://github.com/vuejs/vuex/commit/7cec79d339b874ec41f35891c891dfd27460c1d3))
# [3.5.0](https://github.com/vuejs/vuex/compare/v4.0.0-beta.2...v3.5.0) (2020-06-29)
# [4.0.0-beta.3](https://github.com/vuejs/vuex/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2020-06-29)
### Bug Fixes
* UMD bundle containing `process.env` flag ([#1749](https://github.com/vuejs/vuex/issues/1749)) ([0fea8c4](https://github.com/vuejs/vuex/commit/0fea8c44060d08b3b421f1ddaa809fdffbc89b00))
### Features
* include `createLogger` function in core export ([afa566d](https://github.com/vuejs/vuex/commit/afa566d7f7b8e516389463b437fbfcb9eafdbd1b))
* include logger plugin to the core export ([#1783](https://github.com/vuejs/vuex/issues/1783)) ([04e2bd8](https://github.com/vuejs/vuex/commit/04e2bd8b3509c67398a6fe73a3d53660069feca8))
# [3.4.0](https://github.com/vuejs/vuex/compare/4.0.0-beta.2...v3.4.0) (2020-05-11)
# [4.0.0-beta.2](https://github.com/vuejs/vuex/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2020-05-11)
### Bug Fixes
- types: add `useStore` function ([#1736](https://github.com/vuejs/vuex/issues/1736)) [#1739](https://github.com/vuejs/vuex/issues/1736)
- build: fix `iife` build containing `process.env`.
# [4.0.0-beta.1](https://github.com/vuejs/vuex/compare/v3.3.0...v4.0.0-beta.1) (2020-04-25)
### Features
- Added TypeScript support.
### Breaking Changes
#### Bundles are now aligned with Vue 3
The bundles are generated as below to align with Vue 3 bundles.
- `vuex.global(.prod).js`
- For direct use via `<script src="...">` in the browser. Exposes the Vuex global.
- Note that global builds are not UMD builds. They are built as IIFEs and is only meant for direct use via `<script src="...">`.
- Contains hard-coded prod/dev branches, and the prod build is pre-minified. Use the `.prod.js` files for production.
- `vuex.esm-browser(.prod).js`
- For usage via native ES modules imports (in browser via `<script type="module">`.
- `vuex.esm-bundler.js`
- For use with bundlers like `webpack`, `rollup` and `parcel`.
- Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).
- Does not ship minified builds (to be done together with the rest of the code after bundling).
- `vuex.cjs.js`
- For use in Node.js server-side rendering via `require()`.
#### Typings for `ComponentCustomProperties`
Vuex 4 removes its global typings for `this.$store` within Vue Component due to solving [issue #994](https://github.com/vuejs/vuex/issues/994). When using TypeScript, you must provide your own augment declaration.
Please place the following code in your project to have `this.$store` working.
```ts
// vuex-shim.d.ts
declare module "@vue/runtime-core" {
// Declare your own store states.
interface State {
count: number
}
interface ComponentCustomProperties {
$store: Store<State>;
}
}
```
# [4.0.0-alpha.1](https://github.com/vuejs/vuex/compare/v3.1.3...v4.0.0-alpha.1) (2020-03-15)
This is the Vue 3 compatible version of Vuex. The focus is compatibility, and it provides the exact same API as Vuex 3, so users can reuse their existing Vuex code for Vue 3.
## Status: Alpha
All Vuex 3 feature works. There are a few breaking changes described in a later section, so please check them out. You can find basic usage with both option and composition API at `example` folder.
Please note that it's still unstable, and there might be bugs. Please provide us feedback if you find anything. You may use [vue-next-webpack-preview](https://github.com/vuejs/vue-next-webpack-preview) to test out Vue 3 with Vuex 4.
## Breaking changes
### Installation process has changed
To align with the new Vue 3 initialization process, the installation process of Vuex has changed as well.
You should use a new `createStore` function to create a new store instance.
```js
import { createStore } from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
}
})
```
> This is technically not a breaking change because you could still use `new Store(...)` syntax. However, to align with Vue 3 and also with Vue Router Next, we recommend users to use `createStore` function instead.
Then to install Vuex to Vue app instance, pass the store instance instead of Vuex.
```js
import { createApp } from 'vue'
import store from './store'
import App from './APP.vue'
const app = createApp(Counter)
app.use(store)
app.mount('#app')
```
## Kown issues
- The code is kept as close to Vuex 3 code base as possible, and there're plenty of places where we should refactor. However, we are waiting for all of the test cases to pass before doing so (some tests require Vue 3 update).
- TypeScript support is not ready yet. Please use JS environment to test this for now.
# [3.4.0](https://github.com/vuejs/vuex/compare/v3.3.0...v3.4.0) (2020-05-11)
### Features
* Allow action subscribers to catch rejections. ([#1740](https://github.com/vuejs/vuex/issues/1740)) ([6ebbe64](https://github.com/vuejs/vuex/commit/6ebbe64c5821d19e55a41dc8b1d81cfce6cbd195)), closes [#1489](https://github.com/vuejs/vuex/issues/1489) [#1558](https://github.com/vuejs/vuex/issues/1558) [#1625](https://github.com/vuejs/vuex/issues/1625)
# [3.3.0](https://github.com/vuejs/vuex/compare/v3.2.0...v3.3.0) (2020-04-25)
### Bug Fixes
* Prepend devtool handler ([#1358](https://github.com/vuejs/vuex/issues/1358)) ([a39d076](https://github.com/vuejs/vuex/commit/a39d0767e4041cdd5cf8050774106c01d39024e0)), closes [vuejs/vue-devtools#678](https://github.com/vuejs/vue-devtools/issues/678)
* **types:** Add `devtools` to store options type ([#1478](https://github.com/vuejs/vuex/issues/1478)) ([38c11dc](https://github.com/vuejs/vuex/commit/38c11dcbaea7d7e661a1623cabb5aef7c6e47ba7))
### Features
* Add `prepend` option for `subscribe` and `subscribeAction` ([#1358](https://github.com/vuejs/vuex/issues/1358)) ([a39d076](https://github.com/vuejs/vuex/commit/a39d0767e4041cdd5cf8050774106c01d39024e0))
* **logger:** `createLogger` can optionally log actions ([#987](https://github.com/vuejs/vuex/issues/987)) ([18be128](https://github.com/vuejs/vuex/commit/18be128ad933d1fca6da05c060f7664ce0c819ae))
# [3.2.0](https://github.com/vuejs/vuex/compare/v3.1.3...v3.2.0) (2020-04-19)
### Features
* add Store#hasModule(path) API ([#834](https://github.com/vuejs/vuex/issues/834)) ([d65d142](https://github.com/vuejs/vuex/commit/d65d14276e87aca17cfbd3fbf4af9e8dbb808f24))
## [3.1.3](https://github.com/vuejs/vuex/compare/v3.1.2...v3.1.3) (2020-03-09)
### Bug Fixes
* Prevent invalidating subscription iterator ([#1438](https://github.com/vuejs/vuex/issues/1438)) ([e012653](https://github.com/vuejs/vuex/commit/e0126533301febf66072f1865cf9a77778cf2176))
## [3.1.2](https://github.com/vuejs/vuex/compare/v3.1.1...v3.1.2) (2019-11-10)
### Bug Fixes
* tweak mapping helper warning message ([#1641](https://github.com/vuejs/vuex/issues/1641)) ([e60bc76](https://github.com/vuejs/vuex/commit/e60bc76154bb05c12b24342617b946d9a6e2f476))
* **types:** avoid broadening vue instance type when using map helpers ([#1639](https://github.com/vuejs/vuex/issues/1639)) ([9a96720](https://github.com/vuejs/vuex/commit/9a9672050bcfee198c379069ec0e1b03ca6cb965))
* add warnings when the different namespaced modules has the same names… ([#1554](https://github.com/vuejs/vuex/issues/1554)) ([91f3e69](https://github.com/vuejs/vuex/commit/91f3e69ed9e290cf91f8885c6d5ae2c97fa7ab81))
* Should vuex mapState print error message [#1093](https://github.com/vuejs/vuex/issues/1093) ([#1297](https://github.com/vuejs/vuex/issues/1297)) ([e5ca2d5](https://github.com/vuejs/vuex/commit/e5ca2d52e89a126bd48bd8a6003be77379960ea9))
* Warn about conflicts between state and module ([#1365](https://github.com/vuejs/vuex/issues/1365)) ([538ee58](https://github.com/vuejs/vuex/commit/538ee5803bbca2fc8077208fb30c8d56d8be5cae))
* **docs:** Clearify state object type ([#1601](https://github.com/vuejs/vuex/issues/1601)) ([de06f76](https://github.com/vuejs/vuex/commit/de06f76380e7429489c0eb15acc8e0b34a383860))
### Performance Improvements
* Implementing a cache for the gettersProxy object creation ([#1546](https://github.com/vuejs/vuex/issues/1546)) ([4003382](https://github.com/vuejs/vuex/commit/40033825b7259c2e9b702bdf94e0b24ed4511d7c))
## [3.1.1](https://github.com/vuejs/vuex/compare/v3.1.0...v3.1.1) (2019-05-08)
### Bug Fixes
* Memory leak happening while using registerModule/u… ([#1508](https://github.com/vuejs/vuex/issues/1508)) ([cb9986a](https://github.com/vuejs/vuex/commit/cb9986ae5a62e002a1d876e881ee5f31dd410888)), closes [issue#1507](https://github.com/issue/issues/1507)
* **types:** Make mutation and action payload optional in definition file ([#1517](https://github.com/vuejs/vuex/issues/1517)) ([0e109e2](https://github.com/vuejs/vuex/commit/0e109e2a38dafdc0c2bd6bd3892bc66cfe252b16)), closes [#1491](https://github.com/vuejs/vuex/issues/1491)
### Features
* **devtool:** allow usage in non-browser environments ([#1404](https://github.com/vuejs/vuex/issues/1404)) ([665455f](https://github.com/vuejs/vuex/commit/665455f8daf8512e7adbf63c2842bc0b1e39efdb))
* **esm build:** build ES modules for browser ([#1533](https://github.com/vuejs/vuex/issues/1533)) ([d7c7f98](https://github.com/vuejs/vuex/commit/d7c7f9844831f98c5c9aaca213746c4ccc5d6929))
# [3.1.0](https://github.com/vuejs/vuex/compare/v3.0.1...v3.1.0) (2019-01-17)
### Bug Fixes
* **types:** add helpers to default export type declaration as in sources ([#1408](https://github.com/vuejs/vuex/issues/1408)) ([404d0de](https://github.com/vuejs/vuex/commit/404d0de9531322a1a462e53dfd858d20f0bd99af))
* **types:** add type annotation for the context of actions ([#1322](https://github.com/vuejs/vuex/issues/1322)) ([d1b5c66](https://github.com/vuejs/vuex/commit/d1b5c66961ab53e0172cbc706ff616227bcb5c77))
* **types:** allow a function type for root `state` option ([#1132](https://github.com/vuejs/vuex/issues/1132)) ([d39791b](https://github.com/vuejs/vuex/commit/d39791bd05830b1889705761ef5779449e35e97f))
* Add key to v-for ([#1369](https://github.com/vuejs/vuex/issues/1369)) ([a9bd047](https://github.com/vuejs/vuex/commit/a9bd047ea147cacfcb4003946aeebccd2c5e1e4e))
* avoid to call root state function twice ([#1034](https://github.com/vuejs/vuex/issues/1034)) ([86677eb](https://github.com/vuejs/vuex/commit/86677ebcbfaecf712f339b73a568150fc9fd5f5e))
* fix [#1032](https://github.com/vuejs/vuex/issues/1032), relax vue typing in helpers ([#1044](https://github.com/vuejs/vuex/issues/1044)) ([7c7ed1d](https://github.com/vuejs/vuex/commit/7c7ed1d37ee8a5058082d763d80529e5fef86a0b))
### Features
* add ability to turn off devtools on vuex by passing an off options ([#1407](https://github.com/vuejs/vuex/issues/1407)) ([be75d41](https://github.com/vuejs/vuex/commit/be75d41cf54d50177a7db7e9218e8d1c820ae830))
* ensure errors in action subscribers do not break actions ([acd7249](https://github.com/vuejs/vuex/commit/acd72492eaffff3661f75860a3d7ab37b73c3906))
### Reverts
* Revert "Update util find (#1205)" (fix #1286) ([273bf86](https://github.com/vuejs/vuex/commit/273bf86b330ee580a73176c300919996b7d9c2c3)), closes [#1286](https://github.com/vuejs/vuex/issues/1286)
## [3.0.1](https://github.com/vuejs/vuex/compare/v3.0.0...v3.0.1) (2017-11-01)
# [3.0.0](https://github.com/vuejs/vuex/compare/v2.5.0...v3.0.0) (2017-10-11)
### Features
* **typings:** adapt to the new Vue typings ([#909](https://github.com/vuejs/vuex/issues/909)) ([65dbfec](https://github.com/vuejs/vuex/commit/65dbfec40d5fe7aac05aab333c7b70768997ca7f))
### BREAKING CHANGES
* **typings:** It is no longer compatible with the old Vue typings
* chore(package): bump typescript and vue core typings
* chore: bump vue
* Update package.json
# [2.5.0](https://github.com/vuejs/vuex/compare/v2.4.1...v2.5.0) (2017-10-11)
### Bug Fixes
* initialize root state as an empty object if state function returns no value ([#927](https://github.com/vuejs/vuex/issues/927)) ([0e9756b](https://github.com/vuejs/vuex/commit/0e9756b93c5de8e03286d93f0b50af5f8dfd3bac))
### Features
* add logger plugin logger config support ([#771](https://github.com/vuejs/vuex/issues/771)) ([804c3bb](https://github.com/vuejs/vuex/commit/804c3bbd2e60f11412f5a7cb7694969f8f6c215c))
* preserve state with registerModule ([#837](https://github.com/vuejs/vuex/issues/837)) ([4c1841e](https://github.com/vuejs/vuex/commit/4c1841e79e63ca0ca95d0cc1b218fde258f23c20))
* root actions in namespaced modules ([#941](https://github.com/vuejs/vuex/issues/941)) ([73189eb](https://github.com/vuejs/vuex/commit/73189eb35509de7d49bd2b577900ad560d37dcb0))
* subscribeAction ([#960](https://github.com/vuejs/vuex/issues/960)) ([a8326b1](https://github.com/vuejs/vuex/commit/a8326b1bd77158e7e5903eed4cc98b52599e3dbd))
## [2.4.1](https://github.com/vuejs/vuex/compare/v2.4.0...v2.4.1) (2017-09-27)
### Bug Fixes
* allow installation on extended Vue copies ([c87b72f](https://github.com/vuejs/vuex/commit/c87b72f2ff7f65e708c4b59a752ef234d0f28d1f))
* link to details of mutations in components ([#930](https://github.com/vuejs/vuex/issues/930)) ([e82782b](https://github.com/vuejs/vuex/commit/e82782ba81c398dd5b78a195257a9d1c3a6d85ef))
* move auto installation code into the store constructor ([#914](https://github.com/vuejs/vuex/issues/914)) ([852ac43](https://github.com/vuejs/vuex/commit/852ac43ea4813ecaeb1e5106c4a29c74e57c2fd7))
### Features
* allow to passing functions in mapActions/mapMutations (fix [#750](https://github.com/vuejs/vuex/issues/750)) ([#924](https://github.com/vuejs/vuex/issues/924)) ([be15f32](https://github.com/vuejs/vuex/commit/be15f32c0077d8fe9bafa38c1b319b655cfd5f86))
# [2.4.0](https://github.com/vuejs/vuex/compare/v2.3.0...v2.4.0) (2017-08-29)
### Bug Fixes
* **typings:** watch() returns an unwatch function ([#922](https://github.com/vuejs/vuex/issues/922)) ([a4bd081](https://github.com/vuejs/vuex/commit/a4bd0816838cc4a843d833363b9aa412c1256e5e))
* add missing typings and docs of createNamespacedHelpers ([#910](https://github.com/vuejs/vuex/issues/910)) ([7ad573b](https://github.com/vuejs/vuex/commit/7ad573bba59d23dbd66e3a25e6614296aeb98d42))
### Features
* **store:** bind mutation and action handlers to store ([#872](https://github.com/vuejs/vuex/issues/872)) ([67da622](https://github.com/vuejs/vuex/commit/67da6225552e46266ed059c7f0d0128294cd08ed))
### Performance Improvements
* do not connect devtools if Vue.config.devtools == false ([#881](https://github.com/vuejs/vuex/issues/881)) ([dd7f817](https://github.com/vuejs/vuex/commit/dd7f8178d93e6121a447c410b9c652f40cd80937))
# [2.3.0](https://github.com/vuejs/vuex/compare/v2.2.1...v2.3.0) (2017-04-13)
* Add '-loader' suffix to webpack config (#722) ([84b4634](https://github.com/vuejs/vuex/commit/84b463438ea4133f7f326dc18212e3d4b7b5a177)), closes [#722](https://github.com/vuejs/vuex/issues/722)
### BREAKING CHANGES
* It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'babel-loader' instead of 'babel'.
My version of webpack: 2.2.0-rc.3
Adding the '-loader' suffix fixed the problem.
Not sure though how safe it is to use 'babel-loader' instead of 'babel' with previous webpack versions...
## [2.2.1](https://github.com/vuejs/vuex/compare/v2.2.0...v2.2.1) (2017-02-26)
# [2.2.0](https://github.com/vuejs/vuex/compare/v2.1.2...v2.2.0) (2017-02-26)
## [2.1.2](https://github.com/vuejs/vuex/compare/v2.1.1...v2.1.2) (2017-02-06)
### Reverts
* Revert "Update modules.md (#534)" ([5e145b3](https://github.com/vuejs/vuex/commit/5e145b3a2d45977b52cfff41b3b663f629d67e74)), closes [#534](https://github.com/vuejs/vuex/issues/534)
## [2.1.1](https://github.com/vuejs/vuex/compare/v2.1.0...v2.1.1) (2016-12-17)
# [2.1.0](https://github.com/vuejs/vuex/compare/v2.0.0...v2.1.0) (2016-12-16)
# [2.0.0](https://github.com/vuejs/vuex/compare/v2.0.0-rc.6...v2.0.0) (2016-09-30)
# [2.0.0-rc.6](https://github.com/vuejs/vuex/compare/v2.0.0-rc.5...v2.0.0-rc.6) (2016-09-24)
# [2.0.0-rc.5](https://github.com/vuejs/vuex/compare/v2.0.0-rc.4...v2.0.0-rc.5) (2016-08-15)
# [2.0.0-rc.4](https://github.com/vuejs/vuex/compare/v2.0.0-rc.3...v2.0.0-rc.4) (2016-08-05)
# [2.0.0-rc.3](https://github.com/vuejs/vuex/compare/v2.0.0-rc.1...v2.0.0-rc.3) (2016-07-11)
# [2.0.0-rc.1](https://github.com/vuejs/vuex/compare/v1.0.0-rc...v2.0.0-rc.1) (2016-07-05)
# [1.0.0-rc](https://github.com/vuejs/vuex/compare/v0.8.2...v1.0.0-rc) (2016-07-01)
## [0.8.2](https://github.com/vuejs/vuex/compare/v0.8.1...v0.8.2) (2016-06-28)
## [0.8.1](https://github.com/vuejs/vuex/compare/v0.8.0...v0.8.1) (2016-06-28)
# [0.8.0](https://github.com/vuejs/vuex/compare/v0.7.1...v0.8.0) (2016-06-23)
## [0.7.1](https://github.com/vuejs/vuex/compare/v0.7.0...v0.7.1) (2016-06-22)
# [0.7.0](https://github.com/vuejs/vuex/compare/v0.6.3...v0.7.0) (2016-06-21)
## [0.6.3](https://github.com/vuejs/vuex/compare/v0.6.2...v0.6.3) (2016-04-23)
## [0.6.2](https://github.com/vuejs/vuex/compare/v0.6.1...v0.6.2) (2016-03-08)
## [0.6.1](https://github.com/vuejs/vuex/compare/v0.6.0...v0.6.1) (2016-03-07)
# [0.6.0](https://github.com/vuejs/vuex/compare/v0.5.1...v0.6.0) (2016-03-07)
## [0.5.1](https://github.com/vuejs/vuex/compare/v0.5.0...v0.5.1) (2016-03-04)
# [0.5.0](https://github.com/vuejs/vuex/compare/v0.4.2...v0.5.0) (2016-03-04)
## [0.4.2](https://github.com/vuejs/vuex/compare/v0.4.1...v0.4.2) (2016-03-02)
## [0.4.1](https://github.com/vuejs/vuex/compare/v0.4.0...v0.4.1) (2016-03-01)
# [0.4.0](https://github.com/vuejs/vuex/compare/v0.3.0...v0.4.0) (2016-03-01)
# [0.3.0](https://github.com/vuejs/vuex/compare/4a22523b8cf4a1954ec95a0083ddef6c085f4905...v0.3.0) (2016-02-16)
### Bug Fixes
* **api:** fix typo ([4a22523](https://github.com/vuejs/vuex/commit/4a22523b8cf4a1954ec95a0083ddef6c085f4905))
* **forms:** fix typo ([50094a6](https://github.com/vuejs/vuex/commit/50094a604f32d00ceb784a3fbf07c82c502faca2))
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015-present Evan You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# Vuex
[](https://npmjs.com/package/vuex)
[](https://github.com/vuejs/vuex/actions/workflows/ci.yml)
---
**Pinia is now the new default**
The official state management library for Vue has changed to [Pinia](https://pinia.vuejs.org). Pinia has almost the exact same or enhanced API as Vuex 5, described in [Vuex 5 RFC](https://github.com/vuejs/rfcs/pull/271). You could simply consider Pinia as Vuex 5 with a different name. Pinia also works with Vue 2.x as well.
Vuex 3 and 4 will still be maintained. However, it's unlikely to add new functionalities to it. Vuex and Pinia can be installed in the same project. If you're migrating existing Vuex app to Pinia, it might be a suitable option. However, if you're planning to start a new project, we highly recommend using Pinia instead.
---
Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official [devtools extension](https://github.com/vuejs/vue-devtools) to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.
Learn more about Vuex at "[What is Vuex?](https://vuex.vuejs.org/)", or get started by looking into [full documentation](http://vuex.vuejs.org/).
## Documentation
To check out docs, visit [vuex.vuejs.org](https://vuex.vuejs.org/).
## Examples
You may find example applications built with Vuex under the `examples` directory.
Running the examples:
```bash
$ npm install
$ npm run dev # serve examples at localhost:8080
```
## Questions
For questions and support please use the [Discord chat server](https://chat.vuejs.org) or [the official forum](http://forum.vuejs.org). The issue list of this repo is **exclusively** for bug reports and feature requests.
## Issues
Please make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vuex/blob/main/.github/contributing.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/vuejs/vuex/releases).
## Stay In Touch
For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs).
## Contribution
Please make sure to read the [Contributing Guide](https://github.com/vuejs/vuex/blob/main/.github/contributing.md) before making a pull request.
## License
[MIT](http://opensource.org/licenses/MIT)
Copyright (c) 2015-present Evan You
================================================
FILE: docs/.vitepress/config.js
================================================
module.exports = {
lang: 'en-US',
title: 'Vuex',
description: 'Centralized State Management for Vue.js',
locales: {
'/': {
lang: 'en-US',
title: 'Vuex',
description: 'Centralized State Management for Vue.js'
},
'/zh/': {
lang: 'zh-CN',
title: 'Vuex',
description: 'Vue.js 的中心化状态管理方案'
},
'/ja/': {
lang: 'ja',
title: 'Vuex',
description: 'Vue.js のための集中状態管理'
},
'/ptbr/': {
lang: 'pt-BR',
title: 'Vuex',
description: 'Gerenciamento de Estado Centralizado para Vue.js'
}
},
head: [
['link', { rel: 'icon', href: `/logo.png` }],
['link', { rel: 'apple-touch-icon', href: `/icons/apple-touch-icon-152x152.png` }],
['link', { rel: 'mask-icon', href: '/icons/safari-pinned-tab.svg', color: '#3eaf7c' }],
['meta', { name: 'msapplication-TileImage', content: '/icons/msapplication-icon-144x144.png' }]
],
themeConfig: {
repo: 'vuejs/vuex',
docsDir: 'docs',
docsBranch: 'main',
editLinks: true,
locales: {
'/': {
label: 'English',
selectText: 'Languages',
editLinkText: 'Edit this page on GitHub',
lastUpdated: 'Last Updated',
nav: [
{ text: 'Guide', link: '/guide/' },
{ text: 'API Reference', link: '/api/' },
{ text: 'Release Notes', link: 'https://github.com/vuejs/vuex/releases' },
{
text: 'v4.x',
items: [
{ text: 'v3.x', link: 'https://v3.vuex.vuejs.org/' }
]
}
],
sidebar: [
{
text: 'Introduction',
children: [
{ text: 'What is Vuex?', link: '/' },
{ text: 'Installation', link: '/installation' },
{ text: 'Getting Started', link: '/guide/' }
]
},
{
text: 'Core Concepts',
children: [
{ text: 'State', link: '/guide/state' },
{ text: 'Getters', link: '/guide/getters' },
{ text: 'Mutations', link: '/guide/mutations' },
{ text: 'Actions', link: '/guide/actions' },
{ text: 'Modules', link: '/guide/modules' }
]
},
{
text: 'Advanced',
children: [
{ text: 'Application Structure', link: '/guide/structure' },
{ text: 'Composition API', link: '/guide/composition-api' },
{ text: 'Plugins', link: '/guide/plugins' },
{ text: 'Strict Mode', link: '/guide/strict' },
{ text: 'Form Handling', link: '/guide/forms' },
{ text: 'Testing', link: '/guide/testing' },
{ text: 'Hot Reloading', link: '/guide/hot-reload' },
{ text: 'TypeScript Support', link: '/guide/typescript-support' },
]
},
{
text: 'Migration Guide',
children: [
{ text: 'Migrating to 4.0 from 3.x', link: '/guide/migrating-to-4-0-from-3-x' }
]
}
]
},
'/zh/': {
label: '简体中文',
selectText: '选择语言',
editLinkText: '在 GitHub 上编辑此页',
lastUpdated: '最近更新时间',
nav: [
{ text: '指南', link: '/zh/guide/' },
{ text: 'API 参考', link: '/zh/api/' },
{ text: '更新记录', link: 'https://github.com/vuejs/vuex/releases' },
{
text: 'v4.x',
items: [
{ text: 'v3.x', link: 'https://v3.vuex.vuejs.org/zh' }
]
}
],
sidebar: [
{
text: '介绍',
children: [
{ text: 'Vuex 是什么?', link: '/zh/' },
{ text: '安装', link: '/zh/installation' },
{ text: '开始', link: '/zh/guide/' }
]
},
{
text: '核心概念',
children: [
{ text: 'State', link: '/zh/guide/state' },
{ text: 'Getter', link: '/zh/guide/getters' },
{ text: 'Mutation', link: '/zh/guide/mutations' },
{ text: 'Action', link: '/zh/guide/actions' },
{ text: 'Module', link: '/zh/guide/modules' }
]
},
{
text: '进阶',
children: [
{ text: '项目结构', link: '/zh/guide/structure' },
{ text: '组合式 API', link: '/zh/guide/composition-api' },
{ text: '插件', link: '/zh/guide/plugins' },
{ text: '严格模式', link: '/zh/guide/strict' },
{ text: '表单处理', link: '/zh/guide/forms' },
{ text: '测试', link: '/zh/guide/testing' },
{ text: '热重载', link: '/zh/guide/hot-reload' },
{ text: 'TypeScript 支持', link: '/zh/guide/typescript-support' },
]
},
{
text: '迁移指南',
children: [
{ text: '从 3.x 迁移到 4.0', link: '/zh/guide/migrating-to-4-0-from-3-x' }
]
}
]
},
'/ja/': {
label: '日本語',
selectText: '言語',
editLinkText: 'GitHub 上でこのページを編集する',
lastUpdated: '最終更新日時',
nav: [
{ text: 'ガイド', link: '/ja/guide/' },
{ text: 'API リファレンス', link: '/ja/api/' },
{ text: 'リリースノート', link: 'https://github.com/vuejs/vuex/releases' },
{
text: 'v4.x',
items: [
{ text: 'v3.x', link: 'https://v3.vuex.vuejs.org/ja' }
]
}
],
sidebar: [
{
text: 'はじめに',
children: [
{ text: 'Vuex とは何か?', link: '/ja/' },
{ text: 'インストール', link: '/ja/installation' },
{ text: 'Vuex 入門', link: '/ja/guide/' }
]
},
{
text: 'コアコンセプト',
children: [
{ text: 'ステート', link: '/ja/guide/state' },
{ text: 'ゲッター', link: '/ja/guide/getters' },
{ text: 'ミューテーション', link: '/ja/guide/mutations' },
{ text: 'アクション', link: '/ja/guide/actions' },
{ text: 'モジュール', link: '/ja/guide/modules' }
]
},
{
text: '高度な活用',
children: [
{ text: 'アプリケーションの構造', link: '/ja/guide/structure' },
{ text: 'Composition API', link: '/ja/guide/composition-api' },
{ text: 'プラグイン', link: '/ja/guide/plugins' },
{ text: '厳格モード', link: '/ja/guide/strict' },
{ text: 'フォームの扱い', link: '/ja/guide/forms' },
{ text: 'テスト', link: '/ja/guide/testing' },
{ text: 'ホットリローディング', link: '/ja/guide/hot-reload' },
{ text: 'TypeScript サポート', link: '/ja/guide/typescript-support' },
]
},
{
text: '移行 ガイド',
children: [
{ text: '3.x から 4.0 への移行', link: '/ja/guide/migrating-to-4-0-from-3-x' }
]
}
]
},
'/ptbr/': {
label: 'Português',
selectText: 'Idiomas',
editLinkText: 'Edite esta página no GitHub',
lastUpdated: 'Última Atualização',
nav: [
{ text: 'Guia', link: '/ptbr/guide/' },
{ text: 'Referência da API', link: '/ptbr/api/' },
{ text: 'Notas de Lançamento', link: 'https://github.com/vuejs/vuex/releases' },
{
text: 'v4.x',
items: [
{ text: 'v3.x', link: 'https://v3.vuex.vuejs.org/ptbr/' }
]
}
],
sidebar: [
{
text: 'Introdução',
children: [
{ text: 'O que é Vuex?', link: '/ptbr/' },
{ text: 'Instalação', link: '/ptbr/installation' },
{ text: 'Começando', link: '/ptbr/guide/' }
]
},
{
text: 'Conceitos Básicos',
children: [
{ text: 'Estado', link: '/ptbr/guide/state' },
{ text: 'Getters', link: '/ptbr/guide/getters' },
{ text: 'Mutações', link: '/ptbr/guide/mutations' },
{ text: 'Ações', link: '/ptbr/guide/actions' },
{ text: 'Módulos', link: '/ptbr/guide/modules' }
]
},
{
text: 'Avançado',
children: [
{ text: 'Estrutura da Aplicação', link: '/ptbr/guide/structure' },
{ text: 'Composition API', link: '/ptbr/guide/composition-api' },
{ text: 'Plugins', link: '/ptbr/guide/plugins' },
{ text: 'Modo Strict', link: '/ptbr/guide/strict' },
{ text: 'Manipulação de Formulários', link: '/ptbr/guide/forms' },
{ text: 'Testando', link: '/ptbr/guide/testing' },
{ text: 'Hot Reloading', link: '/ptbr/guide/hot-reload' },
{ text: 'Suporte ao TypeScript', link: '/ptbr/guide/typescript-support' },
]
},
{
text: 'Guia de Migração',
children: [
{ text: 'Migrando do 3.x para 4.0', link: '/ptbr/guide/migrating-to-4-0-from-3-x' }
]
}
]
}
}
}
}
================================================
FILE: docs/.vitepress/styles/styles.css
================================================
.scrimba {
position: relative;
margin-top: 16px;
border-radius: 2px;
padding: 1em 1.25em;
color: #486491;
background-color: #e7ecf3;
}
.scrimba a {
position: relative;
padding-left: 36px;
color: #486491 !important;
}
.scrimba a::before {
position: absolute;
top: -5px;
left: -4px;
display: block;
border-radius: 50%;
width: 30px;
height: 30px;
background-color: #73abfe;
content: "";
}
.scrimba a::after {
position: absolute;
top: 5px;
left: 8px;
display: block;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 8px solid #ffffff;
width: 0;
height: 0;
content: "";
}
================================================
FILE: docs/.vitepress/theme/index.js
================================================
import '../styles/styles.css'
import DefaultTheme from 'vitepress/dist/client/theme-default'
export default {
...DefaultTheme
}
================================================
FILE: docs/api/index.md
================================================
---
sidebar: auto
---
# API Reference
## Store
### createStore
- `createStore<S>(options: StoreOptions<S>): Store<S>`
Creates a new store.
```js
import { createStore } from 'vuex'
const store = createStore({ ...options })
```
## Store Constructor Options
### state
- type: `Object | Function`
The root state object for the Vuex store. [Details](../guide/state.md)
If you pass a function that returns an object, the returned object is used as the root state. This is useful when you want to reuse the state object especially for module reuse. [Details](../guide/modules.md#module-reuse)
### mutations
- type: `{ [type: string]: Function }`
Register mutations on the store. The handler function always receives `state` as the first argument (will be module local state if defined in a module), and receives a second `payload` argument if there is one.
[Details](../guide/mutations.md)
### actions
- type: `{ [type: string]: Function }`
Register actions on the store. The handler function receives a `context` object that exposes the following properties:
```js
{
state, // same as `store.state`, or local state if in modules
rootState, // same as `store.state`, only in modules
commit, // same as `store.commit`
dispatch, // same as `store.dispatch`
getters, // same as `store.getters`, or local getters if in modules
rootGetters // same as `store.getters`, only in modules
}
```
And also receives a second `payload` argument if there is one.
[Details](../guide/actions.md)
### getters
- type: `{ [key: string]: Function }`
Register getters on the store. The getter function receives the following arguments:
```
state, // will be module local state if defined in a module.
getters // same as store.getters
```
Specific when defined in a module
```
state, // will be module local state if defined in a module.
getters, // module local getters of the current module
rootState, // global state
rootGetters // all getters
```
Registered getters are exposed on `store.getters`.
[Details](../guide/getters.md)
### modules
- type: `Object`
An object containing sub modules to be merged into the store, in the shape of:
```js
{
key: {
state,
namespaced?,
mutations?,
actions?,
getters?,
modules?
},
...
}
```
Each module can contain `state` and `mutations` similar to the root options. A module's state will be attached to the store's root state using the module's key. A module's mutations and getters will only receives the module's local state as the first argument instead of the root state, and module actions' `context.state` will also point to the local state.
[Details](../guide/modules.md)
### plugins
- type: `Array<Function>`
An array of plugin functions to be applied to the store. The plugin simply receives the store as the only argument and can either listen to mutations (for outbound data persistence, logging, or debugging) or dispatch mutations (for inbound data e.g. websockets or observables).
[Details](../guide/plugins.md)
### strict
- type: `boolean`
- default: `false`
Force the Vuex store into strict mode. In strict mode any mutations to Vuex state outside of mutation handlers will throw an Error.
[Details](../guide/strict.md)
### devtools
- type: `boolean`
Turn the devtools on or off for a particular Vuex instance. For instance, passing `false` tells the Vuex store to not subscribe to devtools plugin. Useful when you have multiple stores on a single page.
```js
{
devtools: false
}
```
## Store Instance Properties
### state
- type: `Object`
The root state. Read only.
### getters
- type: `Object`
Exposes registered getters. Read only.
## Store Instance Methods
### commit
- `commit(type: string, payload?: any, options?: Object)`
- `commit(mutation: Object, options?: Object)`
Commit a mutation. `options` can have `root: true` that allows to commit root mutations in [namespaced modules](../guide/modules.md#namespacing). [Details](../guide/mutations.md)
### dispatch
- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
- `dispatch(action: Object, options?: Object): Promise<any>`
Dispatch an action. `options` can have `root: true` that allows to dispatch root actions in [namespaced modules](../guide/modules.md#namespacing). Returns a Promise that resolves all triggered action handlers. [Details](../guide/actions.md)
### replaceState
- `replaceState(state: Object)`
Replace the store's root state. Use this only for state hydration / time-travel purposes.
### watch
- `watch(fn: Function, callback: Function, options?: Object): Function`
Reactively watch `fn`'s return value, and call the callback when the value changes. `fn` receives the store's state as the first argument, and getters as the second argument. Accepts an optional options object that takes the same options as [Vue's `vm.$watch` method](https://vuejs.org/v2/api/#vm-watch).
To stop watching, call the returned unwatch function.
### subscribe
- `subscribe(handler: Function, options?: Object): Function`
Subscribe to store mutations. The `handler` is called after every mutation and receives the mutation descriptor and post-mutation state as arguments.
```js
const unsubscribe = store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
// you may call unsubscribe to stop the subscription
unsubscribe()
```
By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overridden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.
```js
store.subscribe(handler, { prepend: true })
```
The `subscribe` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, you might subscribe to a Vuex Module and unsubscribe when you unregister the module. Or you might call `subscribe` from inside a Vue Component and then destroy the component later. In these cases, you should remember to unsubscribe the subscription manually.
Most commonly used in plugins. [Details](../guide/plugins.md)
### subscribeAction
- `subscribeAction(handler: Function, options?: Object): Function`
Subscribe to store actions. The `handler` is called for every dispatched action and receives the action descriptor and current store state as arguments.
The `subscribe` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, when unregistering a Vuex module or before destroying a Vue component.
```js
const unsubscribe = store.subscribeAction((action, state) => {
console.log(action.type)
console.log(action.payload)
})
// you may call unsubscribe to stop the subscription
unsubscribe()
```
By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overridden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.
```js
store.subscribeAction(handler, { prepend: true })
```
The `subscribeAction` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, you might subscribe to a Vuex Module and unsubscribe when you unregister the module. Or you might call `subscribeAction` from inside a Vue Component and then destroy the component later. In these cases, you should remember to unsubscribe the subscription manually.
`subscribeAction` can also specify whether the subscribe handler should be called *before* or *after* an action dispatch (the default behavior is *before*):
```js
store.subscribeAction({
before: (action, state) => {
console.log(`before action ${action.type}`)
},
after: (action, state) => {
console.log(`after action ${action.type}`)
}
})
```
`subscribeAction` can also specify an `error` handler to catch an error thrown when an action is dispatched. The function will receive an `error` object as the third argument.
```js
store.subscribeAction({
error: (action, state, error) => {
console.log(`error action ${action.type}`)
console.error(error)
}
})
```
The `subscribeAction` method is most commonly used in plugins. [Details](../guide/plugins.md)
### registerModule
- `registerModule(path: string | Array<string>, module: Module, options?: Object)`
Register a dynamic module. [Details](../guide/modules.md#dynamic-module-registration)
`options` can have `preserveState: true` that allows to preserve the previous state. Useful with Server Side Rendering.
### unregisterModule
- `unregisterModule(path: string | Array<string>)`
Unregister a dynamic module. [Details](../guide/modules.md#dynamic-module-registration)
### hasModule
- `hasModule(path: string | Array<string>): boolean`
Check if the module with the given name is already registered. [Details](../guide/modules.md#dynamic-module-registration)
### hotUpdate
- `hotUpdate(newOptions: Object)`
Hot swap new actions and mutations. [Details](../guide/hot-reload.md)
## Component Binding Helpers
### mapState
- `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`
Create component computed options that return the sub tree of the Vuex store. [Details](../guide/state.md#the-mapstate-helper)
The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)
The second object argument's members can be a function. `function(state: any)`
### mapGetters
- `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`
Create component computed options that return the evaluated value of a getter. [Details](../guide/getters.md#the-mapgetters-helper)
The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)
### mapActions
- `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`
Create component methods options that dispatch an action. [Details](../guide/actions.md#dispatching-actions-in-components)
The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)
The second object argument's members can be a function. `function(dispatch: function, ...args: any[])`
### mapMutations
- `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`
Create component methods options that commit a mutation. [Details](../guide/mutations.md#committing-mutations-in-components)
The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)
The second object argument's members can be a function. `function(commit: function, ...args: any[])`
### createNamespacedHelpers
- `createNamespacedHelpers(namespace: string): Object`
Create namespaced component binding helpers. The returned object contains `mapState`, `mapGetters`, `mapActions` and `mapMutations` that are bound with the given namespace. [Details](../guide/modules.md#binding-helpers-with-namespace)
## Composable Functions
### useStore
- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`
Fetches the injected store when called inside the `setup` hook. When using the Composition API, you can retrieve the store by calling this method.
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
TypeScript users can use an injection key to retrieve a typed store. In order for this to work, you must define the injection key and pass it along with the store when installing the store instance to the Vue app.
First, declare the injection key using Vue's `InjectionKey` interface.
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
export interface State {
count: number
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
```
Then, pass the defined key as the second argument for the `app.use` method.
```ts
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
app.use(store, key)
app.mount('#app')
```
Finally, you can pass the key to the `useStore` method to retrieve the typed store instance.
```ts
// in a vue component
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // typed as number
}
}
```
================================================
FILE: docs/guide/actions.md
================================================
# Actions
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c6ggR3cG" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
Actions are similar to mutations, the differences being that:
- Instead of mutating the state, actions commit mutations.
- Actions can contain arbitrary asynchronous operations.
Let's register a simple action:
``` js
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
```
Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call `context.commit` to commit a mutation, or access the state and getters via `context.state` and `context.getters`. We can even call other actions with `context.dispatch`. We will see why this context object is not the store instance itself when we introduce [Modules](modules.md) later.
In practice, we often use ES2015 [argument destructuring](https://github.com/lukehoban/es6features#destructuring) to simplify the code a bit (especially when we need to call `commit` multiple times):
``` js
actions: {
increment ({ commit }) {
commit('increment')
}
}
```
## Dispatching Actions
Actions are triggered with the `store.dispatch` method:
``` js
store.dispatch('increment')
```
This may look silly at first sight: if we want to increment the count, why don't we just call `store.commit('increment')` directly? Remember that **mutations have to be synchronous**. Actions don't. We can perform **asynchronous** operations inside an action:
``` js
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
```
Actions support the same payload format and object-style dispatch:
``` js
// dispatch with a payload
store.dispatch('incrementAsync', {
amount: 10
})
// dispatch with an object
store.dispatch({
type: 'incrementAsync',
amount: 10
})
```
A more practical example of real-world actions would be an action to checkout a shopping cart, which involves **calling an async API** and **committing multiple mutations**:
``` js
actions: {
checkout ({ commit, state }, products) {
// save the items currently in the cart
const savedCartItems = [...state.cart.added]
// send out checkout request, and optimistically
// clear the cart
commit(types.CHECKOUT_REQUEST)
// the shop API accepts a success callback and a failure callback
shop.buyProducts(
products,
// handle success
() => commit(types.CHECKOUT_SUCCESS),
// handle failure
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
```
Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them.
## Dispatching Actions in Components
You can dispatch actions in components with `this.$store.dispatch('xxx')`, or use the `mapActions` helper which maps component methods to `store.dispatch` calls (requires root `store` injection):
``` js
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // map `this.increment()` to `this.$store.dispatch('increment')`
// `mapActions` also supports payloads:
'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
})
}
}
```
## Composing Actions
Actions are often asynchronous, so how do we know when an action is done? And more importantly, how can we compose multiple actions together to handle more complex async flows?
The first thing to know is that `store.dispatch` can handle Promise returned by the triggered action handler and it also returns Promise:
``` js
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
```
Now you can do:
``` js
store.dispatch('actionA').then(() => {
// ...
})
```
And also in another action:
``` js
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
```
Finally, if we make use of [async / await](https://tc39.github.io/ecmascript-asyncawait/), we can compose our actions like this:
``` js
// assuming `getData()` and `getOtherData()` return Promises
actions: {
async actionA ({ commit }) {
commit('gotData', await getData())
},
async actionB ({ dispatch, commit }) {
await dispatch('actionA') // wait for `actionA` to finish
commit('gotOtherData', await getOtherData())
}
}
```
> It's possible for a `store.dispatch` to trigger multiple action handlers in different modules. In such a case the returned value will be a Promise that resolves when all triggered handlers have been resolved.
================================================
FILE: docs/guide/composition-api.md
================================================
# Composition API
To access the store within the `setup` hook, you can call the `useStore` function. This is the equivalent of retrieving `this.$store` within a component using the Option API.
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
## Accessing State and Getters
In order to access state and getters, you will want to create `computed` references to retain reactivity. This is the equivalent of creating computed properties using the Option API.
```js
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// access a state in computed function
count: computed(() => store.state.count),
// access a getter in computed function
double: computed(() => store.getters.double)
}
}
}
```
## Accessing Mutations and Actions
When accessing mutations and actions, you can simply provide the `commit` and `dispatch` method inside the `setup` hook.
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// access a mutation
increment: () => store.commit('increment'),
// access an action
asyncIncrement: () => store.dispatch('asyncIncrement')
}
}
}
```
## Examples
Check out the [Composition API example](https://github.com/vuejs/vuex/tree/4.0/examples/composition) to see example applications utilizing Vuex and Vue's Composition API.
================================================
FILE: docs/guide/forms.md
================================================
# Form Handling
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cqKRgEC9" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
When using Vuex in strict mode, it could be a bit tricky to use `v-model` on a piece of state that belongs to Vuex:
``` html
<input v-model="obj.message">
```
Assuming `obj` is a computed property that returns an Object from the store, the `v-model` here will attempt to directly mutate `obj.message` when the user types in the input. In strict mode, this will result in an error because the mutation is not performed inside an explicit Vuex mutation handler.
The "Vuex way" to deal with it is binding the `<input>`'s value and call a method on the `input` or `change` event:
``` html
<input :value="message" @input="updateMessage">
```
``` js
// ...
computed: {
...mapState({
message: state => state.obj.message
})
},
methods: {
updateMessage (e) {
this.$store.commit('updateMessage', e.target.value)
}
}
```
And here's the mutation handler:
``` js
// ...
mutations: {
updateMessage (state, message) {
state.obj.message = message
}
}
```
## Two-way Computed Property
Admittedly, the above is quite a bit more verbose than `v-model` + local state, and we lose some of the useful features from `v-model` as well. An alternative approach is using a two-way computed property with a setter:
``` html
<input v-model="message">
```
``` js
// ...
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
```
================================================
FILE: docs/guide/getters.md
================================================
# Getters
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c2Be7TB" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
Sometimes we may need to compute derived state based on store state, for example filtering through a list of items and counting them:
``` js
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
```
If more than one component needs to make use of this, we have to either duplicate the function, or extract it into a shared helper and import it in multiple places - both are less than ideal.
Vuex allows us to define "getters" in the store. You can think of them as computed properties for stores.
::: warning WARNING
As of Vue 3.0, the getter's result is **not cached** as the computed property does. This is a known issue that requires Vue 3.1 to be released. You can learn more at [PR #1878](https://github.com/vuejs/vuex/pull/1878).
:::
Getters will receive the state as their 1st argument:
``` js
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos (state) {
return state.todos.filter(todo => todo.done)
}
}
})
```
## Property-Style Access
The getters will be exposed on the `store.getters` object, and you access values as properties:
``` js
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
```
Getters will also receive other getters as the 2nd argument:
``` js
getters: {
// ...
doneTodosCount (state, getters) {
return getters.doneTodos.length
}
}
```
``` js
store.getters.doneTodosCount // -> 1
```
We can now easily make use of it inside any component:
``` js
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
```
Note that getters accessed as properties are cached as part of Vue's reactivity system.
## Method-Style Access
You can also pass arguments to getters by returning a function. This is particularly useful when you want to query an array in the store:
```js
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
```
``` js
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
```
Note that getters accessed via methods will run each time you call them, and the result is not cached.
## The `mapGetters` Helper
The `mapGetters` helper simply maps store getters to local computed properties:
``` js
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// mix the getters into computed with object spread operator
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
```
If you want to map a getter to a different name, use an object:
``` js
...mapGetters({
// map `this.doneCount` to `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
```
================================================
FILE: docs/guide/hot-reload.md
================================================
# Hot Reloading
Vuex supports hot-reloading mutations, modules, actions and getters during development, using webpack's [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/). You can also use it in Browserify with the [browserify-hmr](https://github.com/AgentME/browserify-hmr/) plugin.
For mutations and modules, you need to use the `store.hotUpdate()` API method:
``` js
// store.js
import { createStore } from 'vuex'
import mutations from './mutations'
import moduleA from './modules/a'
const state = { ... }
const store = createStore({
state,
mutations,
modules: {
a: moduleA
}
})
if (module.hot) {
// accept actions and mutations as hot modules
module.hot.accept(['./mutations', './modules/a'], () => {
// require the updated modules
// have to add .default here due to babel 6 module output
const newMutations = require('./mutations').default
const newModuleA = require('./modules/a').default
// swap in the new modules and mutations
store.hotUpdate({
mutations: newMutations,
modules: {
a: newModuleA
}
})
})
}
```
Checkout the [counter-hot example](https://github.com/vuejs/vuex/tree/main/examples/counter-hot) to play with hot-reload.
## Dynamic module hot reloading
If you use modules exclusively, you can use `require.context` to load and hot reload all modules dynamically.
```js
// store.js
import { createStore } from 'vuex'
// Load all modules.
function loadModules() {
const context = require.context("./modules", false, /([a-z_]+)\.js$/i)
const modules = context
.keys()
.map((key) => ({ key, name: key.match(/([a-z_]+)\.js$/i)[1] }))
.reduce(
(modules, { key, name }) => ({
...modules,
[name]: context(key).default
}),
{}
)
return { context, modules }
}
const { context, modules } = loadModules()
const store = createStore({
modules
})
if (module.hot) {
// Hot reload whenever any module changes.
module.hot.accept(context.id, () => {
const { modules } = loadModules()
store.hotUpdate({
modules
})
})
}
```
================================================
FILE: docs/guide/index.md
================================================
# Getting Started
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cMPa2Uk" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
At the center of every Vuex application is the **store**. A "store" is basically a container that holds your application **state**. There are two things that make a Vuex store different from a plain global object:
1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes.
2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly **committing mutations**. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications.
## The Simplest Store
:::tip NOTE
We will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)!
:::
After [installing](../installation.md) Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations:
```js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// Create a new store instance.
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
const app = createApp({ /* your root component */ })
// Install the store instance as a plugin
app.use(store)
```
Now, you can access the state object as `store.state`, and trigger a state change with the `store.commit` method:
```js
store.commit('increment')
console.log(store.state.count) // -> 1
```
In a Vue component, you can access the store as `this.$store`. Now we can commit a mutation using a component method:
```js
methods: {
increment() {
this.$store.commit('increment')
console.log(this.$store.state.count)
}
}
```
Again, the reason we are committing a mutation instead of changing `store.state.count` directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging.
Using store state in a component simply involves returning the state within a computed property, because the store state is reactive. Triggering changes simply means committing mutations in component methods.
Next, we will discuss each core concept in much finer details, starting with [State](state.md).
================================================
FILE: docs/guide/migrating-to-4-0-from-3-x.md
================================================
# Migrating to 4.0 from 3.x
Almost all Vuex 4 APIs have remained unchanged from Vuex 3. However, there are still a few breaking changes that you must fix.
- [Breaking Changes](#breaking-changes)
- [Installation process](#installation-process)
- [TypeScript support](#typescript-support)
- [Bundles are now aligned with Vue 3](#bundles-are-now-aligned-with-vue-3)
- ["createLogger" function is exported from the core module](#createlogger-function-is-exported-from-the-core-module)
- [New Features](#new-features)
- [New "useStore" composition function](#new-usestore-composition-function)
## Breaking Changes
### Installation process
To align with the new Vue 3 initialization process, the installation process of Vuex has changed. To create a new store, users are now encouraged to use the newly introduced createStore function.
```js
import { createStore } from 'vuex'
export const store = createStore({
state () {
return {
count: 1
}
}
})
```
To install Vuex to a Vue instance, pass the `store` instead of Vuex.
```js
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.mount('#app')
```
:::tip NOTE
Whilst this is not technically a breaking change, you may still use the `new Store(...)` syntax, we recommend this approach to align with Vue 3 and Vue Router Next.
:::
### TypeScript support
Vuex 4 removes its global typings for `this.$store` within a Vue component to solve [issue #994](https://github.com/vuejs/vuex/issues/994). When used with TypeScript, you must declare your own module augmentation.
Place the following code in your project to allow `this.$store` to be typed correctly:
```ts
// vuex-shim.d.ts
import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'
declare module 'vue' {
// Declare your own store states.
interface State {
count: number
}
interface ComponentCustomProperties {
$store: Store<State>
}
}
```
You can learn more in the [TypeScript Support](./typescript-support) section.
### Bundles are now aligned with Vue 3
The following bundles are generated to align with Vue 3 bundles:
- `vuex.global(.prod).js`
- For direct use with `<script src="...">` in the browser. Exposes the Vuex global.
- Global build is built as IIFE, and not UMD, and is only meant for direct use with `<script src="...">`.
- Contains hard-coded prod/dev branches and the prod build is pre-minified. Use the `.prod.js` files for production.
- `vuex.esm-browser(.prod).js`
- For use with native ES module imports (including module supporting browsers via `<script type="module">`.
- `vuex.esm-bundler.js`
- For use with bundlers such as `webpack`, `rollup` and `parcel`.
- Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).
- Does not ship minified builds (to be done together with the rest of the code after bundling).
- `vuex.cjs.js`
- For use in Node.js server-side rendering with `require()`.
### `createLogger` function is exported from the core module
In Vuex 3, `createLogger` function was exported from `vuex/dist/logger` but it's now included in the core package. The function should be imported directly from the `vuex` package.
```js
import { createLogger } from 'vuex'
```
## New Features
### New `useStore` composition function
Vuex 4 introduces a new API to interact with the store in Composition API. You can use the `useStore` composition function to retrieve the store within the component `setup` hook.
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
You can learn more in the [Composition API](./composition-api) section.
================================================
FILE: docs/guide/modules.md
================================================
# Modules
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cqKK4psq" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
Due to using a single state tree, all states of our application are contained inside one big object. However, as our application grows in scale, the store can get really bloated.
To help with that, Vuex allows us to divide our store into **modules**. Each module can contain its own state, mutations, actions, getters, and even nested modules - it's fractal all the way down:
```js
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
```
## Module Local State
Inside a module's mutations and getters, the first argument received will be **the module's local state**.
```js
const moduleA = {
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// `state` is the local module state
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
```
Similarly, inside module actions, `context.state` will expose the local state, and root state will be exposed as `context.rootState`:
```js
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
```
Also, inside module getters, the root state will be exposed as their 3rd argument:
```js
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
```
## Namespacing
By default, actions and mutations are still registered under the **global namespace** - this allows multiple modules to react to the same action/mutation type. Getters are also registered in the global namespace by default. However, this currently has no functional purpose (it's as is to avoid breaking changes). You must be careful not to define two getters with the same name in different, non-namespaced modules, resulting in an error.
If you want your modules to be more self-contained or reusable, you can mark it as namespaced with `namespaced: true`. When the module is registered, all of its getters, actions and mutations will be automatically namespaced based on the path the module is registered at. For example:
```js
const store = createStore({
modules: {
account: {
namespaced: true,
// module assets
state: () => ({ ... }), // module state is already nested and not affected by namespace option
getters: {
isAdmin () { ... } // -> getters['account/isAdmin']
},
actions: {
login () { ... } // -> dispatch('account/login')
},
mutations: {
login () { ... } // -> commit('account/login')
},
// nested modules
modules: {
// inherits the namespace from parent module
myPage: {
state: () => ({ ... }),
getters: {
profile () { ... } // -> getters['account/profile']
}
},
// further nest the namespace
posts: {
namespaced: true,
state: () => ({ ... }),
getters: {
popular () { ... } // -> getters['account/posts/popular']
}
}
}
}
}
})
```
Namespaced getters and actions will receive localized `getters`, `dispatch` and `commit`. In other words, you can use the module assets without writing prefix in the same module. Toggling between namespaced or not does not affect the code inside the module.
### Accessing Global Assets in Namespaced Modules
If you want to use global state and getters, `rootState` and `rootGetters` are passed as the 3rd and 4th arguments to getter functions, and also exposed as properties on the `context` object passed to action functions.
To dispatch actions or commit mutations in the global namespace, pass `{ root: true }` as the 3rd argument to `dispatch` and `commit`.
```js
modules: {
foo: {
namespaced: true,
getters: {
// `getters` is localized to this module's getters
// you can use rootGetters via 4th argument of getters
someGetter (state, getters, rootState, rootGetters) {
getters.someOtherGetter // -> 'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'
},
someOtherGetter: state => { ... }
},
actions: {
// dispatch and commit are also localized for this module
// they will accept `root` option for the root dispatch/commit
someAction ({ dispatch, commit, getters, rootGetters }) {
getters.someGetter // -> 'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
rootGetters['bar/someGetter'] // -> 'bar/someGetter'
dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'
},
someOtherAction (ctx, payload) { ... }
}
}
}
```
### Register Global Action in Namespaced Modules
If you want to register global actions in namespaced modules, you can mark it with `root: true` and place the action definition to function `handler`. For example:
```js
{
actions: {
someOtherAction ({dispatch}) {
dispatch('someAction')
}
},
modules: {
foo: {
namespaced: true,
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 'someAction'
}
}
}
}
}
```
### Binding Helpers with Namespace
When binding a namespaced module to components with the `mapState`, `mapGetters`, `mapActions` and `mapMutations` helpers, it can get a bit verbose:
```js
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
}),
...mapGetters([
'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']
'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']
])
},
methods: {
...mapActions([
'some/nested/module/foo', // -> this['some/nested/module/foo']()
'some/nested/module/bar' // -> this['some/nested/module/bar']()
])
}
```
In such cases, you can pass the module namespace string as the first argument to the helpers so that all bindings are done using that module as the context. The above can be simplified to:
```js
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
}),
...mapGetters('some/nested/module', [
'someGetter', // -> this.someGetter
'someOtherGetter', // -> this.someOtherGetter
])
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
```
Furthermore, you can create namespaced helpers by using `createNamespacedHelpers`. It returns an object having new component binding helpers that are bound with the given namespace value:
```js
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
export default {
computed: {
// look up in `some/nested/module`
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// look up in `some/nested/module`
...mapActions([
'foo',
'bar'
])
}
}
```
### Caveat for Plugin Developers
You may care about unpredictable namespacing for your modules when you create a [plugin](plugins.md) that provides the modules and let users add them to a Vuex store. Your modules will be also namespaced if the plugin users add your modules under a namespaced module. To adapt this situation, you may need to receive a namespace value via your plugin option:
```js
// get namespace value via plugin option
// and returns Vuex plugin function
export function createPlugin (options = {}) {
return function (store) {
// add namespace to plugin module's types
const namespace = options.namespace || ''
store.dispatch(namespace + 'pluginAction')
}
}
```
## Dynamic Module Registration
You can register a module **after** the store has been created with the `store.registerModule` method:
```js
import { createStore } from 'vuex'
const store = createStore({ /* options */ })
// register a module `myModule`
store.registerModule('myModule', {
// ...
})
// register a nested module `nested/myModule`
store.registerModule(['nested', 'myModule'], {
// ...
})
```
The module's state will be exposed as `store.state.myModule` and `store.state.nested.myModule`.
Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) library integrates vue-router with vuex by managing the application's route state in a dynamically attached module.
You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method.
Note that you may check if the module is already registered to the store or not via `store.hasModule(moduleName)` method. One thing to keep in mind is that nested modules should be passed as arrays for both the `registerModule` and `hasModule` and not as a string with the path to the module.
### Preserving state
It may be likely that you want to preserve the previous state when registering a new module, such as preserving state from a Server Side Rendered app. You can achieve this with `preserveState` option: `store.registerModule('a', module, { preserveState: true })`
When you set `preserveState: true`, the module is registered, actions, mutations and getters are added to the store, but the state is not. It's assumed that your store state already contains state for that module and you don't want to overwrite it.
## Module Reuse
Sometimes we may need to create multiple instances of a module, for example:
- Creating multiple stores that use the same module (e.g. To [avoid stateful singletons in the SSR](https://ssr.vuejs.org/en/structure.html#avoid-stateful-singletons) when the `runInNewContext` option is `false` or `'once'`);
- Register the same module multiple times in the same store.
If we use a plain object to declare the state of the module, then that state object will be shared by reference and cause cross store/module state pollution when it's mutated.
This is actually the exact same problem with `data` inside Vue components. So the solution is also the same - use a function for declaring module state (supported in 2.3.0+):
```js
const MyReusableModule = {
state: () => ({
foo: 'bar'
}),
// mutations, actions, getters...
}
```
================================================
FILE: docs/guide/mutations.md
================================================
# Mutations
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/ckMZp4HN" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
The only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string **type** and a **handler**. The handler function is where we perform actual state modifications, and it will receive the state as the first argument:
```js
const store = createStore({
state: {
count: 1
},
mutations: {
increment (state) {
// mutate state
state.count++
}
}
})
```
You cannot directly call a mutation handler. Think of it more like event registration: "When a mutation with type `increment` is triggered, call this handler." To invoke a mutation handler, you need to call `store.commit` with its type:
```js
store.commit('increment')
```
## Commit with Payload
You can pass an additional argument to `store.commit`, which is called the **payload** for the mutation:
```js
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
```
```js
store.commit('increment', 10)
```
In most cases, the payload should be an object so that it can contain multiple fields, and the recorded mutation will also be more descriptive:
```js
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
```
```js
store.commit('increment', {
amount: 10
})
```
## Object-Style Commit
An alternative way to commit a mutation is by directly using an object that has a `type` property:
```js
store.commit({
type: 'increment',
amount: 10
})
```
When using object-style commit, the entire object will be passed as the payload to mutation handlers, so the handler remains the same:
```js
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
```
## Using Constants for Mutation Types
It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allows the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application:
```js
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
```
```js
// store.js
import { createStore } from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = createStore({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
```
Whether to use constants is largely a preference - it can be helpful in large projects with many developers, but it's totally optional if you don't like them.
## Mutations Must Be Synchronous
One important rule to remember is that **mutation handler functions must be synchronous**. Why? Consider the following example:
```js
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
```
Now imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a "before" and "after" snapshots of the state. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called - any state mutation performed in the callback is essentially un-trackable!
## Committing Mutations in Components
You can commit mutations in components with `this.$store.commit('xxx')`, or use the `mapMutations` helper which maps component methods to `store.commit` calls (requires root `store` injection):
```js
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // map `this.increment()` to `this.$store.commit('increment')`
// `mapMutations` also supports payloads:
'incrementBy' // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // map `this.add()` to `this.$store.commit('increment')`
})
}
}
```
## On to Actions
Asynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both with async callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, **mutations are synchronous transactions**:
```js
store.commit('increment')
// any state change that the "increment" mutation may cause
// should be done at this moment.
```
To handle asynchronous operations, let's introduce [Actions](actions.md).
================================================
FILE: docs/guide/plugins.md
================================================
# Plugins
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cvp8ZkCR" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
Vuex stores accept the `plugins` option that exposes hooks for each mutation. A Vuex plugin is simply a function that receives the store as the only argument:
```js
const myPlugin = (store) => {
// called when the store is initialized
store.subscribe((mutation, state) => {
// called after every mutation.
// The mutation comes in the format of `{ type, payload }`.
})
}
```
And can be used like this:
```js
const store = createStore({
// ...
plugins: [myPlugin]
})
```
## Committing Mutations Inside Plugins
Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations.
By committing mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createWebSocketPlugin` function can take some additional options for more complex tasks):
```js
export default function createWebSocketPlugin (socket) {
return (store) => {
socket.on('data', data => {
store.commit('receiveData', data)
})
store.subscribe(mutation => {
if (mutation.type === 'UPDATE_DATA') {
socket.emit('update', mutation.payload)
}
})
}
}
```
```js
const plugin = createWebSocketPlugin(socket)
const store = createStore({
state,
mutations,
plugins: [plugin]
})
```
## Taking State Snapshots
Sometimes a plugin may want to receive "snapshots" of the state, and also compare the post-mutation state with pre-mutation state. To achieve that, you will need to perform a deep-copy on the state object:
```js
const myPluginWithSnapshot = (store) => {
let prevState = _.cloneDeep(store.state)
store.subscribe((mutation, state) => {
let nextState = _.cloneDeep(state)
// compare `prevState` and `nextState`...
// save state for next mutation
prevState = nextState
})
}
```
**Plugins that take state snapshots should be used only during development.** When using webpack or Browserify, we can let our build tools handle that for us:
```js
const store = createStore({
// ...
plugins: process.env.NODE_ENV !== 'production'
? [myPluginWithSnapshot]
: []
})
```
The plugin will be used by default. For production, you will need [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) for webpack or [envify](https://github.com/hughsk/envify) for Browserify to convert the value of `process.env.NODE_ENV !== 'production'` to `false` for the final build.
## Built-in Logger Plugin
Vuex comes with a logger plugin for common debugging usage:
```js
import { createLogger } from 'vuex'
const store = createStore({
plugins: [createLogger()]
})
```
The `createLogger` function takes a few options:
```js
const logger = createLogger({
collapsed: false, // auto-expand logged mutations
filter (mutation, stateBefore, stateAfter) {
// returns `true` if a mutation should be logged
// `mutation` is a `{ type, payload }`
return mutation.type !== "aBlocklistedMutation"
},
actionFilter (action, state) {
// same as `filter` but for actions
// `action` is a `{ type, payload }`
return action.type !== "aBlocklistedAction"
},
transformer (state) {
// transform the state before logging it.
// for example return only a specific sub-tree
return state.subTree
},
mutationTransformer (mutation) {
// mutations are logged in the format of `{ type, payload }`
// we can format it any way we want.
return mutation.type
},
actionTransformer (action) {
// Same as mutationTransformer but for actions
return action.type
},
logActions: true, // Log Actions
logMutations: true, // Log mutations
logger: console, // implementation of the `console` API, default `console`
})
```
The logger file can also be included directly via a `<script>` tag, and will expose the `createVuexLogger` function globally.
Note the logger plugin takes state snapshots, so use it only during development.
================================================
FILE: docs/guide/state.md
================================================
# State
## Single State Tree
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cWw3Zhb" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
Vuex uses a **single state tree** - that is, this single object contains all your application level state and serves as the "single source of truth." This also means usually you will have only one store for each application. A single state tree makes it straightforward to locate a specific piece of state, and allows us to easily take snapshots of the current app state for debugging purposes.
The single state tree does not conflict with modularity - in later chapters we will discuss how to split your state and mutations into sub modules.
The data you store in Vuex follows the same rules as the `data` in a Vue instance, ie the state object must be plain. **See also:** [Vue#data](https://v3.vuejs.org/api/options-data.html#data-2).
## Getting Vuex State into Vue Components
So how do we display state inside the store in our Vue components? Since Vuex stores are reactive, the simplest way to "retrieve" state from it is simply returning some store state from within a [computed property](https://vuejs.org/guide/computed.html):
```js
// let's create a Counter component
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
```
Whenever `store.state.count` changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates.
However, this pattern causes the component to rely on the global store singleton. When using a module system, it requires importing the store in every component that uses store state, and also requires mocking when testing the component.
Vuex "injects" the store into all child components from the root component through Vue's plugin system, and will be available on them as `this.$store`. Let's update our `Counter` implementation:
```js
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
```
## The `mapState` Helper
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c8Pz7BSK" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
When a component needs to make use of multiple store state properties or getters, declaring all these computed properties can get repetitive and verbose. To deal with this we can make use of the `mapState` helper which generates computed getter functions for us, saving us some keystrokes:
```js
// in full builds helpers are exposed as Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// arrow functions can make the code very succinct!
count: state => state.count,
// passing the string value 'count' is same as `state => state.count`
countAlias: 'count',
// to access local state with `this`, a normal function must be used
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
```
We can also pass a string array to `mapState` when the name of a mapped computed property is the same as a state sub tree name.
```js
computed: mapState([
// map this.count to store.state.count
'count'
])
```
## Object Spread Operator
Note that `mapState` returns an object. How do we use it in combination with other local computed properties? Normally, we'd have to use a utility to merge multiple objects into one so that we can pass the final object to `computed`. However with the [object spread operator](https://github.com/tc39/proposal-object-rest-spread), we can greatly simplify the syntax:
```js
computed: {
localComputed () { /* ... */ },
// mix this into the outer object with the object spread operator
...mapState({
// ...
})
}
```
## Components Can Still Have Local State
Using Vuex doesn't mean you should put **all** the state in Vuex. Although putting more state into Vuex makes your state mutations more explicit and debuggable, sometimes it could also make the code more verbose and indirect. If a piece of state strictly belongs to a single component, it could be just fine leaving it as local state. You should weigh the trade-offs and make decisions that fit the development needs of your app.
================================================
FILE: docs/guide/strict.md
================================================
# Strict Mode
To enable strict mode, simply pass in `strict: true` when creating a Vuex store:
```js
const store = createStore({
// ...
strict: true
})
```
In strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations can be explicitly tracked by debugging tools.
## Development vs. Production
**Do not enable strict mode when deploying for production!** Strict mode runs a synchronous deep watcher on the state tree for detecting inappropriate mutations, and it can be quite expensive when you make large amount of mutations to the state. Make sure to turn it off in production to avoid the performance cost.
Similar to plugins, we can let the build tools handle that:
```js
const store = createStore({
// ...
strict: process.env.NODE_ENV !== 'production'
})
```
================================================
FILE: docs/guide/structure.md
================================================
# Application Structure
Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:
1. Application-level state is centralized in the store.
2. The only way to mutate the state is by committing **mutations**, which are synchronous transactions.
3. Asynchronous logic should be encapsulated in, and can be composed with **actions**.
As long as you follow these rules, it's up to you how to structure your project. If your store file gets too big, simply start splitting the actions, mutations and getters into separate files.
For any non-trivial app, we will likely need to leverage modules. Here's an example project structure:
```bash
├── index.html
├── main.js
├── api
│ └── ... # abstractions for making API requests
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # where we assemble modules and export the store
├── actions.js # root actions
├── mutations.js # root mutations
└── modules
├── cart.js # cart module
└── products.js # products module
```
As a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart).
================================================
FILE: docs/guide/testing.md
================================================
# Testing
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cPGkpJhq" target="_blank" rel="noopener noreferrer">Try this lesson on Scrimba</a></div>
The main parts we want to unit test in Vuex are mutations and actions.
## Testing Mutations
Mutations are very straightforward to test, because they are just functions that completely rely on their arguments. One trick is that if you are using ES2015 modules and put your mutations inside your `store.js` file, in addition to the default export, you should also export the mutations as a named export:
```js
const state = { ... }
// export `mutations` as a named export
export const mutations = { ... }
export default createStore({
state,
mutations
})
```
Example testing a mutation using Mocha + Chai (you can use any framework/assertion libraries you like):
```js
// mutations.js
export const mutations = {
increment: state => state.count++
}
```
```js
// mutations.spec.js
import { expect } from 'chai'
import { mutations } from './store'
// destructure assign `mutations`
const { increment } = mutations
describe('mutations', () => {
it('INCREMENT', () => {
// mock state
const state = { count: 0 }
// apply mutation
increment(state)
// assert result
expect(state.count).to.equal(1)
})
})
```
## Testing Actions
Actions can be a bit more tricky because they may call out to external APIs. When testing actions, we usually need to do some level of mocking - for example, we can abstract the API calls into a service and mock that service inside our tests. In order to easily mock dependencies, we can use webpack and [inject-loader](https://github.com/plasticine/inject-loader) to bundle our test files.
Example testing an async action:
```js
// actions.js
import shop from '../api/shop'
export const getAllProducts = ({ commit }) => {
commit('REQUEST_PRODUCTS')
shop.getProducts(products => {
commit('RECEIVE_PRODUCTS', products)
})
}
```
```js
// actions.spec.js
// use require syntax for inline loaders.
// with inject-loader, this returns a module factory
// that allows us to inject mocked dependencies.
import { expect } from 'chai'
const actionsInjector = require('inject-loader!./actions')
// create the module with our mocks
const actions = actionsInjector({
'../api/shop': {
getProducts (cb) {
setTimeout(() => {
cb([ /* mocked response */ ])
}, 100)
}
}
})
// helper for testing action with expected mutations
const testAction = (action, payload, state, expectedMutations, done) => {
let count = 0
// mock commit
const commit = (type, payload) => {
const mutation = expectedMutations[count]
try {
expect(type).to.equal(mutation.type)
expect(payload).to.deep.equal(mutation.payload)
} catch (error) {
done(error)
}
count++
if (count >= expectedMutations.length) {
done()
}
}
// call the action with mocked store and arguments
action({ commit, state }, payload)
// check if no mutations should have been dispatched
if (expectedMutations.length === 0) {
expect(count).to.equal(0)
done()
}
}
describe('actions', () => {
it('getAllProducts', done => {
testAction(actions.getAllProducts, null, {}, [
{ type: 'REQUEST_PRODUCTS' },
{ type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
], done)
})
})
```
If you have spies available in your testing environment (for example via [Sinon.JS](http://sinonjs.org/)), you can use them instead of the `testAction` helper:
```js
describe('actions', () => {
it('getAllProducts', () => {
const commit = sinon.spy()
const state = {}
actions.getAllProducts({ commit, state })
expect(commit.args).to.deep.equal([
['REQUEST_PRODUCTS'],
['RECEIVE_PRODUCTS', { /* mocked response */ }]
])
})
})
```
## Testing Getters
If your getters have complicated computation, it is worth testing them. Getters are also very straightforward to test for the same reason as mutations.
Example testing a getter:
```js
// getters.js
export const getters = {
filteredProducts (state, { filterCategory }) {
return state.products.filter(product => {
return product.category === filterCategory
})
}
}
```
```js
// getters.spec.js
import { expect } from 'chai'
import { getters } from './getters'
describe('getters', () => {
it('filteredProducts', () => {
// mock state
const state = {
products: [
{ id: 1, title: 'Apple', category: 'fruit' },
{ id: 2, title: 'Orange', category: 'fruit' },
{ id: 3, title: 'Carrot', category: 'vegetable' }
]
}
// mock getter
const filterCategory = 'fruit'
// get the result from the getter
const result = getters.filteredProducts(state, { filterCategory })
// assert the result
expect(result).to.deep.equal([
{ id: 1, title: 'Apple', category: 'fruit' },
{ id: 2, title: 'Orange', category: 'fruit' }
])
})
})
```
## Running Tests
If your mutations and actions are written properly, the tests should have no direct dependency on Browser APIs after proper mocking. Thus you can simply bundle the tests with webpack and run it directly in Node. Alternatively, you can use `mocha-loader` or Karma + `karma-webpack` to run the tests in real browsers.
### Running in Node
Create the following webpack config (together with proper [`.babelrc`](https://babeljs.io/docs/usage/babelrc/)):
```js
// webpack.config.js
module.exports = {
entry: './test.js',
output: {
path: __dirname,
filename: 'test-bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
}
```
Then:
``` bash
webpack
mocha test-bundle.js
```
### Running in Browser
1. Install `mocha-loader`.
2. Change the `entry` from the webpack config above to `'mocha-loader!babel-loader!./test.js'`.
3. Start `webpack-dev-server` using the config.
4. Go to `localhost:8080/webpack-dev-server/test-bundle`.
### Running in Browser with Karma + karma-webpack
Consult the setup in [vue-loader documentation](https://vue-loader.vuejs.org/en/workflow/testing.html).
================================================
FILE: docs/guide/typescript-support.md
================================================
# TypeScript Support
Vuex provides its typings so you can use TypeScript to write a store definition. You don't need any special TypeScript configuration for Vuex. Please follow [Vue's basic TypeScript setup](https://v3.vuejs.org/guide/typescript-support.html) to configure your project.
However, if you're writing your Vue components in TypeScript, there're a few steps to follow that require for you to correctly provide typings for a store.
## Typing `$store` Property in Vue Component
Vuex doesn't provide typings for `this.$store` property out of the box. When used with TypeScript, you must declare your own module augmentation.
To do so, declare custom typings for Vue's `ComponentCustomProperties` by adding a declaration file in your project folder:
```ts
// vuex.d.ts
import { Store } from 'vuex'
declare module 'vue' {
// declare your own store states
interface State {
count: number
}
// provide typings for `this.$store`
interface ComponentCustomProperties {
$store: Store<State>
}
}
```
## Typing `useStore` Composition Function
When you're writing your Vue component in Composition API, you will most likely want `useStore` to return the typed store. For `useStore` to correctly return the typed store, you must:
1. Define the typed `InjectionKey`.
2. Provide the typed `InjectionKey` when installing a store to the Vue app.
3. Pass the typed `InjectionKey` to the `useStore` method.
Let's tackle this step by step. First, define the key using Vue's `InjectionKey` interface along with your own store typing definition:
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
// define your typings for the store state
export interface State {
count: number
}
// define injection key
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
```
Next, pass the defined injection key when installing the store to the Vue app:
```ts
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
// pass the injection key
app.use(store, key)
app.mount('#app')
```
Finally, you can pass the key to the `useStore` method to retrieve the typed store.
```ts
// in a vue component
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // typed as number
}
}
```
Under the hood, Vuex installs the store to the Vue app using Vue's [Provide/Inject](https://v3.vuejs.org/api/composition-api.html#provide-inject) feature which is why the injection key is an important factor.
### Simplifying `useStore` usage
Having to import `InjectionKey` and passing it to `useStore` everywhere it's used can quickly become a repetitive task. To simplify matters, you can define your own composable function to retrieve a typed store:
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
export interface State {
count: number
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
// define your own `useStore` composition function
export function useStore () {
return baseUseStore(key)
}
```
Now, by importing your own composable function, you can retrieve the typed store **without** having to provide the injection key and its typing:
```ts
// in a vue component
import { useStore } from './store'
export default {
setup () {
const store = useStore()
store.state.count // typed as number
}
}
```
================================================
FILE: docs/index.md
================================================
# What is Vuex?
::: tip Pinia is now the new default
The official state management library for Vue has changed to [Pinia](https://pinia.vuejs.org). Pinia has almost the exact same or enhanced API as Vuex 5, described in [Vuex 5 RFC](https://github.com/vuejs/rfcs/pull/271). You could simply consider Pinia as Vuex 5 with a different name. Pinia also works with Vue 2.x as well.
Vuex 3 and 4 will still be maintained. However, it's unlikely to add new functionalities to it. Vuex and Pinia can be installed in the same project. If you're migrating existing Vuex app to Pinia, it might be a suitable option. However, if you're planning to start a new project, we highly recommend using Pinia instead.
:::
Vuex is a **state management pattern + library** for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.
## What is a "State Management Pattern"?
Let's start with a simple Vue counter app:
```js
const Counter = {
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
}
createApp(Counter).mount('#app')
```
It is a self-contained app with the following parts:
- The **state**, the source of truth that drives our app;
- The **view**, a declarative mapping of the **state**;
- The **actions**, the possible ways the state could change in reaction to user inputs from the **view**.
This is a simple representation of the concept of "one-way data flow":
<p style="text-align: center; margin: 2em">
<img style="width:100%; max-width:450px;" src="/flow.png">
</p>
However, the simplicity quickly breaks down when we have **multiple components that share a common state**:
- Multiple views may depend on the same piece of state.
- Actions from different views may need to mutate the same piece of state.
For problem one, passing props can be tedious for deeply nested components, and simply doesn't work for sibling components. For problem two, we often find ourselves resorting to solutions such as reaching for direct parent/child instance references or trying to mutate and synchronize multiple copies of the state via events. Both of these patterns are brittle and quickly lead to unmaintainable code.
So why don't we extract the shared state out of the components, and manage it in a global singleton? With this, our component tree becomes a big "view", and any component can access the state or trigger actions, no matter where they are in the tree!
By defining and separating the concepts involved in state management and enforcing rules that maintain independence between views and states, we give our code more structure and maintainability.
This is the basic idea behind Vuex, inspired by [Flux](https://facebook.github.io/flux/docs/overview), [Redux](http://redux.js.org/) and [The Elm Architecture](https://guide.elm-lang.org/architecture/). Unlike the other patterns, Vuex is also a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates.
If you want to learn Vuex in an interactive way you can check out this [Vuex course on Scrimba](https://scrimba.com/g/gvuex), which gives you a mix of screencast and code playground that you can pause and play around with anytime.

## When Should I Use It?
Vuex helps us deal with shared state management with the cost of more concepts and boilerplate. It's a trade-off between short term and long term productivity.
If you've never built a large-scale SPA and jump right into Vuex, it may feel verbose and daunting. That's perfectly normal - if your app is simple, you will most likely be fine without Vuex. A simple [store pattern](https://v3.vuejs.org/guide/state-management.html#simple-state-management-from-scratch) may be all you need. But if you are building a medium-to-large-scale SPA, chances are you have run into situations that make you think about how to better handle state outside of your Vue components, and Vuex will be the natural next step for you. There's a good quote from Dan Abramov, the author of Redux:
> Flux libraries are like glasses: you’ll know when you need them.
================================================
FILE: docs/installation.md
================================================
# Installation
## Direct Download / CDN
[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)
<!--email_off-->
[Unpkg.com](https://unpkg.com) provides NPM-based CDN links. The above link will always point to the latest release on NPM. You can also use a specific version/tag via URLs like `https://unpkg.com/vuex@4.0.0/dist/vuex.global.js`.
<!--/email_off-->
Include `vuex` after Vue and it will install itself automatically:
```html
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
```
## NPM
```bash
npm install vuex@next --save
```
## Yarn
```bash
yarn add vuex@next --save
```
## Dev Build
You will have to clone directly from GitHub and build `vuex` yourself if you want to use the latest dev build.
```bash
git clone https://github.com/vuejs/vuex.git node_modules/vuex
cd node_modules/vuex
yarn
yarn build
```
================================================
FILE: docs/ja/api/index.md
================================================
---
sidebar: auto
---
# API リファレンス
## Store
### createStore
- `createStore<S>(options: StoreOptions<S>): Store<S>`
新しいストアを作成します。
```js
import { createStore } from 'vuex'
const store = createStore({ ...options })
```
## Store コンストラクタオプション
### state
- 型: `Object | Function`
ストアのための ルートステートオブジェクトです。 [詳細](../guide/state.md)
オブジェクトを返す関数を渡す場合、返されたオブジェクトはルートステートとして使用されます。これは特にモジュールの再利用のためにステートオブジェクトを再利用する場合に便利です。[詳細](../guide/modules.md#モジュールの再利用)
### mutations
- 型: `{ [type: string]: Function }`
ストアにミューテーションを登録します。ハンドラ関数は第 1 引数に `state` を常に受け取り(モジュール内で定義されていれば、モジュールのローカルステートを受け取り)、指定されていれば第 2 引数に `payload` を受け取ります。
[詳細](../guide/mutations.md)
### actions
- 型: `{ [type: string]: Function }`
ストアにアクションを登録します。ハンドラ関数は次のプロパティを持つ `context` オブジェクトを受け取ります。:
```js
{
state, // `store.state` と同じか、モジュール内にあればローカルステート
rootState, // `store.state` と同じ。ただしモジュール内に限る
commit, // `store.commit` と同じ
dispatch, // `store.dispatch` と同じ
getters, // `store.getters` と同じか、モジュール内にあればローカルゲッター
rootGetters // `store.getters` と同じ。ただしモジュール内に限る
}
```
そして、第 2 引数の `payload` があれば、それを受け取ります。
[詳細](../guide/actions.md)
### getters
- 型: `{ [key: string]: Function }`
ストアにゲッターを登録します. ゲッター関数は次の引数を受け取ります:
```
state, // モジュール内で定義されていればモジュールのローカルステート
getters // store.getters と同じ
```
モジュールで定義されたときの仕様
```
state, // モジュールで定義された場合、モジュールのローカルステート
getters, // 現在のモジュールのモジュールのローカルゲッター
rootState, // グローバルステート
rootGetters // 全てのゲッター
```
登録されたゲッターは `store.getters` 上に公開されます。
[詳細](../guide/getters.md)
### modules
- 型: `Object`
サブモジュールを含む次のような形式のオブジェクトはストアにマージされます。
```js
{
key: {
state,
namespaced?,
mutations?,
actions?,
getters?,
modules?
},
...
}
```
各モジュールは、ルートオプションに似た `state` と `mutations` を含むことができます。モジュールの状態は、モジュールのキーを使って、ストアのルートステートに結合されます。モジュールのミューテーションとゲッターは、第 1 引数としてルートステートの代わりに、モジュールのローカルステートだけを受け取り、モジュールのアクションの `context.state` もローカルステートを指すようになります。
[詳細](../guide/modules.md)
### plugins
- 型: `Array<Function>`
プラグイン関数の配列は、ストアに適用されます。このプラグインは、ストアだけを引数として受け取り、外部への永続化、ロギング、デバッギングのために、ミューテーションを監視するか、または、 websocket や observable のような外から渡されるデータのためにミューテーションをディスパッチします。
[詳細](../guide/plugins.md)
### strict
- 型: `boolean`
- デフォルト: `false`
Vuex ストアを厳格モードにします。厳格モードでは、ミューテーションハンドラ以外で、 Vuex の状態の変更を行うと、エラーが投げられます。
[詳細](../guide/strict.md)
### devtools
- 型: `boolean`
特定の Vuex インスタンスに対して開発ツールをオン、またはオフにします。インスタンスに false を渡すと、開発ツールのプラグインを購読しないように Vuex ストアに伝えます。1 ページに複数のストアがある時に便利です。
```js
{
devtools: false
}
```
## Store インスタンスプロパティ
### state
- 型: `Object`
ルートステート、読み取り専用です。
### getters
- 型: `Object`
登録されているゲッターを公開します。読み取り専用です。
## Store インスタンスメソッド
### commit
- `commit(type: string, payload?: any, options?: Object)`
- `commit(mutation: Object, options?: Object)`
ミューテーションをコミットします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なミューテーションにコミットできる `root: true` を持つことできます。[詳細](../guide/mutations.md)
### dispatch
- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
- `dispatch(action: Object, options?: Object): Promise<any>`
アクションをディスパッチします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なアクションにディスパッチできる `root: true` を持つことできます。 すべてのトリガーされたアクションハンドラを解決するPromiseを返します。[詳細](../guide/actions.md)
### replaceState
- `replaceState(state: Object)`
ストアのルートステートを置き換えます。これは、ステートのハイドレーションやタイムトラベルのためだけに利用すべきです。
### watch
- `watch(fn: Function, callback: Function, options?: Object): Function`
`fn`が返す値をリアクティブに監視し、値が変わった時にコールバックを呼びます。`fn`は最初の引数としてストアのステートを、2番目の引数としてゲッターを受け取ります。 [Vue の`vm.$watch`メソッド](https://jp.vuejs.org/v2/api/#watch)と同じオプションをオプションのオブジェクトとして受け付けます。
監視を止める場合は、返された unwatch 関数を呼び出します。
### subscribe
- `subscribe(handler: Function, options?: Object): Function`
ストアへのミューテーションを購読します。`handler` は、全てのミューテーションの後に呼ばれ、引数として、ミューテーション ディスクリプタとミューテーション後の状態を受け取ります。
```js
const unsubscribe = store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
```
デフォルトでは、新しい `handler` はチェーンの最後に登録されます。つまり、先に追加された他の `handler` が呼び出された後に実行されます。`prepend: true` を `options` に設定することで、`handler` をチェーンの最初に登録することができます。
```js
store.subscribe(handler, { prepend: true })
```
購読を停止するには、返された unsubscribe 関数呼び出します。
プラグインの中でもっともよく利用されます。[詳細](../guide/plugins.md)
### subscribeAction
- `subscribeAction(handler: Function, options?: Object): Function`
スストアアクションを購読します。`handler` はディスパッチされたアクションごとに呼び出され、アクション記述子と現在のストア状態を引数として受け取ります:
```js
const unsubscribe = store.subscribeAction((action, state) => {
console.log(action.type)
console.log(action.payload)
})
```
デフォルトでは、新しい `handler` はチェーンの最後に登録されます。つまり、先に追加された他の `handler` が呼び出された後に実行されます。`prepend: true` を `options` に設定することで、`handler` をチェーンの最初に登録することができます。
```js
store.subscribeAction(handler, { prepend: true })
```
購読を停止するには、返された unsubscribe 関数を呼び出します。
`subscribeAction` は購読ハンドラがアクションディスパッチの*前 (before)*、または*後 (after)* に呼びだすべきかどうか(デフォルトの動作は、*before* です)指定することもできます。
```js
store.subscribeAction({
before: (action, state) => {
console.log(`before action ${action.type}`)
},
after: (action, state) => {
console.log(`after action ${action.type}`)
}
})
```
`subscribeAction` は `error` ハンドラを指定することもできます。このハンドラは、アクションディスパッチの中で投げられたエラーをキャッチすることができます。`error` ハンドラは投げられた `error` オブジェクトを第 3 引数として受け取ります。
```js
store.subscribeAction({
error: (action, state, error) => {
console.log(`error action ${action.type}`)
console.error(error)
}
})
```
`subscribeAction` メソッドはプラグインで最も一般的に使用されます。[詳細](../guide/plugins.md)
### registerModule
- `registerModule(path: string | Array<string>, module: Module, options?: Object)`
動的なモジュールを登録します。[詳細](../guide/modules.md#dynamic-module-registration)
`options` は前の状態を保存する `preserveState: true` を持つことができます。サーバサイドレンダリングに役立ちます。
### unregisterModule
- `unregisterModule(path: string | Array<string>)`
動的なモジュールを解除します。[詳細](../guide/modules.md#dynamic-module-registration)
### hasModule
- `hasModule(path: string | Array<string>): boolean`
動的なモジュールがすでに登録されているかどうかを確認します。[詳細](../guide/modules.md#dynamic-module-registration)
### hotUpdate
- `hotUpdate(newOptions: Object)`
新しいアクションとミューテーションをホットスワップします。[詳細](../guide/hot-reload.md)
## コンポーネントをバインドするヘルパー
### mapState
- `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`
ストアのサブツリーを返すコンポーネントの computed オプションを作成します。[詳細](../guide/state.md#the-mapstate-helper)
第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)
第 2 引数のオブジェクトのメンバーには関数 `function(state: any)` を指定できます。
### mapGetters
- `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`
ゲッターの評価後の値を返すコンポーネントの computed オプションを作成します。[詳細](../guide/getters.md#the-mapgetters-helper)
第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)
### mapActions
- `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`
アクションをディスパッチするコンポーネントの methods オプションを作成します。[詳細](../guide/actions.md#dispatching-actions-in-components)
第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)
第 2 引数のオブジェクトのメンバーには関数 `function(dispatch: function, ...args: any[])` を指定できます。
### mapMutations
- `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`
ミューテーションをコミットするコンポーネントの methods オプションを作成します。[詳細](../guide/mutations.md#commiting-mutations-in-components)
第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)
第 2 引数のオブジェクトのメンバーには関数 `function(commit: function, ...args: any[])` を指定できます。
### createNamespacedHelpers
- `createNamespacedHelpers(namespace: string): Object`
名前空間付けられたコンポーネントバインディングのヘルパーを作成します。返されるオブジェクトは指定された名前空間にバインドされた `mapState`、`mapGetters`、`mapActions` そして `mapMutations` が含まれます。[詳細はこちら](../guide/modules.md#binding-helpers-with-namespace)
## Composable 関数
### useStore
- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`
`setup` フックの中で呼ばれた時に、Vue App インスタンスにインストールされたストアを取得します。Composition API を使用する時、このメソッドを呼ぶことでストアを取得することができます。
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
TypeScript ユーザーは、 `InjectionKey` を使って型付けされたストアを取得することができます。そのためには、ストアインスタンスを Vue App インスタンスにインストールする時、`InjectionKey` を定義してストアと一緒に渡す必要があります。
まず、Vue の `InjectionKey` インターフェースを使って、 `InjectionKey` を宣言します。
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
export interface State {
count: number
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
```
次に、定義したキーを `app.use` メソッドの第2引数に渡します。
```ts
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
app.use(store, key)
app.mount('#app')
```
最後に、`useStore` 関数にキーを渡すことで、型付けされたストアインスタンスを取得することができます。
```ts
// vue component 内
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // number として型付け
}
}
```
================================================
FILE: docs/ja/guide/actions.md
================================================
# アクション
<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)で説明します。
実際にはコードを少しシンプルにするために ES2015 の[引数分割束縛(argument destructuring)](https://github.com/lukehoban/es6features#destructuring)がよく使われます(特に `commit` を複数回呼び出す必要があるとき):
``` js
actions: {
increment ({ commit }) {
commit('increment')
}
}
```
## アクションのディスパッチ
アクションは `store.dispatch` がトリガーとなって実行されます:
``` js
store.dispatch('increment')
```
これは一見ばかげて見えるかもしれません。つまり、カウントをインクリメントしたいときに、どうして直接 `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)
// shop API は成功時のコールバックと失敗時のコールバックを受け取る
shop.buyProducts(
products,
// 成功時の処理
() => commit(types.CHECKOUT_SUCCESS),
// 失敗時の処理
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
```
一連の非同期の処理を実行しつつ、ミューテーションのコミットによってのみ副作用(状態の変更)を与えていることに注意してください。
## コンポーネント内でのアクションのディスパッチ
`this.$store.dispatch('xxx')` でコンポーネント内でアクションをディスパッチできます。あるいはコンポーネントのメソッドを `store.dispatch` にマッピングする `mapActions` ヘルパーを使うこともできます(ルートの `store` の注入が必要です):
``` js
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // `this.increment()` を `this.$store.dispatch('increment')` にマッピングする('increment')`
// `mapActions` もペイロードをサポートする:
'incrementBy' // `this.incrementBy(amount)` を `this.$store.dispatch('incrementBy', amount)` にマッピングする
]),
...mapActions({
add: 'increment' // `this.add()` を `this.$store.dispatch('increment')` にマッピングする
})
}
}
```
## アクションを構成する
アクションはしばしば非同期処理を行いますが、アクションが完了したことをどうやって知れば良いのでしょう?そしてもっと重要なことは、さらに複雑な非同期処理を取り扱うために、どうやって複数のアクションを構成させるかということです。
まず知っておくべきことは `store.dispatch` がトリガーされたアクションハンドラによって返された Promise を処理できることと、`store.dispatch` もまた 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 が戻り値として返ってくることになります。
================================================
FILE: docs/ja/guide/composition-api.md
================================================
# Composition API
`setup` フックの中でストアにアクセスするには、`useStore` 関数を呼び出します。これは、Option API を使って、コンポーネント内で `this.$store` を取得するのと同等です。
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
## ステートとゲッターへのアクセス
ステートやゲッターにアクセスするためには、リアクティビティを保持するために `computed` による参照を作成する必要があります。これは、Option API を使って、算出プロパティを作成するのと同じことです。
```js
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// computed 関数のステートにアクセスします
count: computed(() => store.state.count),
// computed 関数のゲッターにアクセスします
double: computed(() => store.getters.double)
}
}
}
```
## ミューテーションとアクションへのアクセス
ミューテーションとアクションにアクセスするには、`setup` フック内で `commit` と `dispatch` 関数を呼び出します。
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// ミューテーションにアクセスする
increment: () => store.commit('increment'),
// アクションにアクセスする
asyncIncrement: () => store.dispatch('asyncIncrement')
}
}
}
```
## Composition API での実装例
Vuex と Vue の Composition API を利用したアプリケーションの例は、[Composition API example](https://github.com/vuejs/vuex/tree/4.0/examples/composition) をご覧ください。
================================================
FILE: docs/ja/guide/forms.md
================================================
# フォームの扱い
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cqKRgEC9" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
厳格モードで Vuex を使用するとき、Vuex に属する状態の一部で `v-model` を使用するのは少しトリッキーです:
``` html
<input v-model="obj.message">
```
`obj` がストアからオブジェクトを返す算出プロパティ (computed property) と仮定すると、`v-model` は input でユーザーが入力するとき、直接 `obj.message` を変更します。厳格モードでは、この変更は明示的に Vuex のミューテーションハンドラ内部で処理されていないため、エラーを投げます。
それに対処するための "Vuex way" は、`<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)
}
}
}
```
================================================
FILE: docs/ja/guide/getters.md
================================================
# ゲッター
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c2Be7TB" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
例えば項目のリストをフィルタリングしたりカウントするときのように、ストアの状態を算出したいときがあります。
``` js
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
```
もしこの関数を複数のコンポーネントで利用したくなったら、関数をコピーするか、あるいは関数を共用のヘルパーに切り出して複数の場所でインポートする必要があります。しかし、どちらも理想的とはいえません。
Vuex を利用するとストア内に "ゲッター" を定義することができます。それらをストアの算出プロパティと考えることができます。
::: warning 警告
Vue 3.0 では、ゲッターの結果は算出プロパティのように**キャッシュされません**。これは既知の問題で、Vue 3.2 がリリースされる必要があります。詳細は [PR #1878](https://github.com/vuejs/vuex/pull/1883) をご確認ください。
:::
ゲッターは第1引数として、state を受け取ります:
``` js
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos (state) {
return state.todos.filter(todo => todo.done)
}
}
})
```
## プロパティスタイルアクセス
ゲッターは `store.getters` オブジェクトから取り出され、プロパティとしてアクセスすることができます:
``` js
store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
```
ゲッターは第2引数として他のゲッターを受け取ります:
``` js
getters: {
// ...
doneTodosCount (state, getters) {
return getters.doneTodos.length
}
}
```
``` js
store.getters.doneTodosCount // -> 1
```
どのコンポーネントの内部でも簡単にゲッターを利用することができます:
``` js
computed: {
doneTodosCount () {
return this.$store.getters.doneTodosCount
}
}
```
プロパティとしてアクセスされるゲッターは Vue のリアクティブシステムの一部としてキャッシュされるという点に留意してください。
## メソッドスタイルアクセス
関数を返り値にすることで、ゲッターに引数を渡すこともできます。これは特にストアの中の配列を検索する時に役立ちます:
```js
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
```
``` js
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
```
メソッドによってアクセスされるゲッターは呼び出す度に実行され、その結果はキャッシュされない点に留意してください。
## `mapGetters` ヘルパー
`mapGetters` ヘルパーはストアのゲッターをローカルの算出プロパティにマッピングさせます:
``` js
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// ゲッターを、スプレッド演算子(object spread operator)を使って computed に組み込む
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
```
ゲッターを異なる名前でマッピングさせたいときはオブジェクトを使います:
``` js
...mapGetters({
// `this.doneCount` を `this.$store.getters.doneTodosCount` にマッピングさせる
doneCount: 'doneTodosCount'
})
```
================================================
FILE: docs/ja/guide/hot-reload.md
================================================
# ホットリローディング
Vuex は webpack の [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/) を使用することで、アプリケーションの開発を行っている間のミューテーション、モジュール、アクション、ゲッターのホットリローディングをサポートします。Browserify では [browserify-hmr](https://github.com/AgentME/browserify-hmr/) プラグインを使用することができます。
ミューテーションとモジュールのホットリローディングのために、`store.hotUpdate()` API メソッドを利用する必要があります:
``` js
// store.js
import { createStore } from 'vuex'
import mutations from './mutations'
import moduleA from './modules/a'
const state = { ... }
const store = createStore({
state,
mutations,
modules: {
a: moduleA
}
})
if (module.hot) {
// ホットモジュールとしてアクションとモジュールを受け付けます
module.hot.accept(['./mutations', './modules/a'], () => {
// 更新されたモジュールをインポートする
// babel 6 のモジュール出力のため、ここでは .default を追加しなければならない
const newMutations = require('./mutations').default
const newModuleA = require('./modules/a').default
// 新しいモジュールとミューテーションにスワップ
store.hotUpdate({
mutations: newMutations,
modules: {
a: newModuleA
}
})
})
}
```
ホットリローディングを試したい場合は、[counter-hot example](https://github.com/vuejs/vuex/tree/main/examples/counter-hot)をチェックアウトしてください。
## 動的モジュールホットリローディング
もしストアでモジュールだけを使用している場合には、`require.context` を使って全てのモジュールを動的に読み込むこともできます。
```js
// store.js
import { createStore } from 'vuex'
// 全てのモジュールをロードする
function loadModules() {
const context = require.context("./modules", false, /([a-z_]+)\.js$/i)
const modules = context
.keys()
.map((key) => ({ key, name: key.match(/([a-z_]+)\.js$/i)[1] }))
.reduce(
(modules, { key, name }) => ({
...modules,
[name]: context(key).default
}),
{}
)
return { context, modules }
}
const { context, modules } = loadModules()
const store = createStore({
modules
})
if (module.hot) {
// モジュールに変更があった場合にホットリロードする
module.hot.accept(context.id, () => {
const { modules } = loadModules()
store.hotUpdate({
modules
})
})
}
```
================================================
FILE: docs/ja/guide/index.md
================================================
# Vuex 入門
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cMPa2Uk" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
Vuex アプリケーションの中心にあるものは**ストア**です。"ストア" は、基本的にアプリケーションの **状態(state)** を保持するコンテナです。単純なグローバルオブジェクトとの違いが 2つあります。
1. Vuex ストアはリアクティブです。Vue コンポーネントがストアから状態を取り出すとき、もしストアの状態が変化したら、ストアはリアクティブかつ効率的に更新を行います。
2. ストアの状態を直接変更することはできません。明示的に**ミューテーションをコミットする**ことによってのみ、ストアの状態を変更します。これによって、全ての状態の変更について追跡可能な記録を残すことが保証され、ツールでのアプリケーションの動作の理解を助けます。
## シンプルなストア
:::tip 注意
私たちは、このドキュメントのコード例に ES2015 のシンタックスを利用しています。 もし触れたことがなければ、[ぜひ触れてください](https://babeljs.io/docs/learn-es2015/)!
:::
Vuex を[インストール](../installation.md) してから、ストアをつくってみましょう。Vuex ストアの作成は、とても簡単です。ストアオブジェクトの初期状態と、いくつかのミューテーションを準備するだけです。
```js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 新しいストアインスタンスを作成します
const store = createStore({
state () {
return {
count: 0
}
},
mutations: {
increment (state) {
state.count++
}
}
})
const app = createApp({ /* ルートコンポーネント */ })
// プラグインとしてストアインスタンスをインストールします
app.use(store)
```
これで `store.state` でストアオブジェクトの状態を参照でき、また `store.commit` メソッドで状態の変更を行うことができます。
```js
store.commit('increment')
console.log(store.state.count) // -> 1
```
Vue コンポーネントでは、`this.$store` としてストアにアクセスできます。それでは、コンポーネントのメソッドを使ってミューテーションをコミットしてみましょう。
```js
methods: {
increment() {
this.$store.commit('increment')
console.log(this.$store.state.count)
}
}
```
そして `store.state.count` を直接変更する代わりにミューテーションをコミットする理由は、状態の変更を明確に追跡したいからです。このシンプルな規約は、あなたのコードの意図をさらに明確にし、コードを読んだ時にアプリケーションの状態の変更について、論理的に考えることができるようにします。加えて、私たちに全ての変更のログを取ったり、状態のスナップショットを取ったり、タイムトラベルデバッグを行うようなツールを実装する余地を与えてくれます。
ストアオブジェクトの状態はリアクティブなので、ストアの状態をコンポーネント内で使うには算出プロパティ内でただ状態を返せば良いです。コンポーネントメソッドでミューテーションをコミットすることによって状態の変更を行います。
これから Vuex のコアコンセプトについて詳しく説明していきます。まずは[状態(state)](state.md)からはじめましょう。
================================================
FILE: docs/ja/guide/migrating-to-4-0-from-3-x.md
================================================
# 3.x から 4.0 への移行
ほとんどすべての Vuex 4 の API は、Vuex 3 から変更されていません。しかし、修正が必要な破壊的変更がいくつかあります。
- [破壊的変更](#破壊的変更)
- [インストール手順](#インストール手順)
- [TypeScript サポート](#typescript-サポート)
- [バンドルが Vue 3 に対応しました](#バンドルが-vue-3-に対応しました)
- ["createLogger" 関数はコアモジュールからエクスポートされます](#createlogger-関数はコアモジュールからエクスポートされます)
- [新機能](#新機能)
- [新しい "useStore" 合成関数](#新しい-usestore-合成関数)
## 破壊的変更
### インストール手順
新しい Vue 3 の初期化の手順に合わせて、Vuex のインストール手順が変更されました。新しいストアを作成するには、新しく導入された createStore 関数を使用することが推奨されます。
```js
import { createStore } from 'vuex'
export const store = createStore({
state () {
return {
count: 1
}
}
})
```
VueインスタンスにVuexをインストールするには、Vuexではなく`store`を渡します。
```js
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'
const app = createApp(App)
app.use(store)
app.mount('#app')
```
:::tip 注意
厳密にはこれは破壊的変更ではなく、まだ `new Store(...)` 構文を使用することができますが、Vue 3 と Vue Router Next に合わせるためにこの方法を推奨します。
:::
### TypeScript サポート
Vuex 4 は、[issue #994](https://github.com/vuejs/vuex/issues/994) を解決するために、Vue コンポーネント内の `this.$store` のグローバルな型付けを削除します。TypeScript で使用する場合は、独自のモジュール拡張を宣言する必要があります。
次のコードをあなたのプロジェクトに配置して、`this.$store` が正しく型付けされるようにしてください。
```ts
// vuex-shim.d.ts
import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'
declare module 'vue' {
// ストアのステートを宣言する
interface State {
count: number
}
interface ComponentCustomProperties {
$store: Store<State>
}
}
```
詳細は、[TypeScript サポート](./typescript-support) セクションをご覧ください.
### バンドルが Vue 3 に対応しました
以下のバンドルは、Vue 3 のバンドルに合わせて生成されます。
- `vuex.global(.prod).js`
- ブラウザの `<script src="...">` で直接使用します。Vuexのグローバルを公開しています。
- グローバルビルドは UMD ではなく IIFE としてビルドされており、`<script src="...">` での直接使用のみを想定しています。
- ハードコードされた prod/dev ブランチが含まれており、prod ビルドはあらかじめ minify されています。本番環境では、`.prod.js` ファイルを使用してください。
- `vuex.esm-browser(.prod).js`
- ネイティブの ES モジュールのインポート(`<script type="module">` でブラウザをサポートするモジュールを含む)で使用されます。
- `vuex.esm-bundler.js`
- `webpack`, `rollup`, `parcel` などのバンドラーで使用されます。
- `process.env.NODE_ENV` のガードを持つ prod/dev ブランチを残します(バンドラーで置き換える必要があります)。
- minify されたビルドは出荷されません(バンドル後に他のコードと一緒に行われます)。
- `vuex.cjs.js`
- Node.js のサーバーサイドレンダリングで、`require()`を使って使用されます。
### "createLogger" 関数はコアモジュールからエクスポートされます
Vuex 3では、`createLogger` 関数は `vuex/dist/logger` からエクスポートされていましたが、現在は core パッケージに含まれています。この関数は `vuex` パッケージから直接インポートする必要があります。
```js
import { createLogger } from 'vuex'
```
## 新機能
### 新しい "useStore" 合成関数
Vuex 4 では、Composition API でストアを操作するための新しい API が導入されました。合成関数の `useStore` を使って、コンポーネントの `setup` フック内でストアを取得することができます。
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
詳細は、[Composition API](./composition-api)のセクションをご覧ください。
================================================
FILE: docs/ja/guide/modules.md
================================================
# モジュール
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cqKK4psq" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
単一ステートツリーを使うため、アプリケーションの全ての状態は、一つの大きなストアオブジェクトに内包されます。しかしながら、アプリケーションが大きくなるにつれて、ストアオブジェクトは膨れ上がってきます。
そのような場合に役立てるため Vuex ではストアを**モジュール**に分割できるようになっています。それぞれのモジュールは、モジュール自身の状態(state)、ミューテーション、アクション、ゲッター、モジュールさえも内包できます(モジュールをネストできます)- トップからボトムまでフラクタル構造です:
```js
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA` のステート
store.state.b // -> `moduleB` のステート
```
## モジュールのローカルステート
モジュールのミューテーションやゲッターの中では、渡される第 1 引数は**モジュールのローカルステート**です。
```js
const moduleA = {
state: () => ({
count: 0
}),
mutations: {
increment (state) {
// `state` はモジュールのローカルステート
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
```
同様に、モジュールのアクションの中では `context.state` はローカルステートにアクセスでき、ルートのステートは `context.rootState` でアクセスできます:
```js
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
```
また、モジュールのゲッターの中では、ルートのステートは第3引数でアクセスできます:
```js
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
```
## 名前空間
デフォルトでは、モジュール内部のアクション、ミューテーション、そしてゲッターは**グローバル名前空間**の元で登録されます - これにより、複数のモジュールが同じミューテーション/アクションタイプに反応することができます。
モジュールをより自己完結型にまた再利用可能なものにしたい場合は、それを `namespaced: true` によって名前空間に分けることができます。モジュールが登録されると、そのゲッター、アクション、およびミューテーションのすべてが、モジュールが登録されているパスに基づいて自動的に名前空間に入れられます。例えば:
```js
const store = createStore({
modules: {
account: {
namespaced: true,
// モジュールのアセット
state: () => ({ ... }), // モジュールステートはすでにネストされており、名前空間のオプションによって影響を受けません
getters: {
isAdmin () { ... } // -> getters['account/isAdmin']
},
actions: {
login () { ... } // -> dispatch('account/login')
},
mutations: {
login () { ... } // -> commit('account/login')
},
// ネストされたモジュール
modules: {
// 親モジュールから名前空間を継承する
myPage: {
state: () => ({ ... }),
getters: {
profile () { ... } // -> getters['account/profile']
}
},
// さらに名前空間をネストする
posts: {
namespaced: true,
state: () => ({ ... }),
getters: {
popular () { ... } // -> getters['account/posts/popular']
}
}
}
}
}
})
```
名前空間のゲッターとアクションは、ローカライズされた `getters`、`dispatch`、`commit` を受け取ります。言い換えれば、同じモジュールに接頭辞 (prefix) を書き込まずに、モジュールアセットを使用することができます。名前空間オプションの切り替えは、モジュール内のコードには影響しません。
### 名前空間付きモジュールでのグローバルアセットへのアクセス
グローバルステートとゲッターを使いたい場合、`rootState` と `rootGetters` はゲッター関数の第3引数と第4引数として渡され、アクション関数に渡される `context` オブジェクトのプロパティとしても公開されます。
アクションをディスパッチするか、グローバル名前空間にミューテーションをコミットするには、`dispatch` と `commit` の3番目の引数として `{root: true}` を渡します。
```js
modules: {
foo: {
namespaced: true,
getters: {
// `getters` はこのモジュールのゲッターにローカライズされています
// ゲッターの第4引数経由で rootGetters を使うことができます
someGetter (state, getters, rootState, rootGetters) {
getters.someOtherGetter // -> 'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'
},
someOtherGetter: state => { ... }
},
actions: {
// ディスパッチとコミットもこのモジュール用にローカライズされています
// ルートディスパッチ/コミットの `root` オプションを受け入れます
someAction ({ dispatch, commit, getters, rootGetters }) {
getters.someGetter // -> 'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
rootGetters['bar/someGetter'] // -> 'bar/someGetter'
dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'
},
someOtherAction (ctx, payload) { ... }
}
}
}
```
### 名前空間付きモジュールでのグローバルアクションへの登録
名前空間付きモジュールでグローバルアクションに登録したい場合、`root: true` でそれをマークでき、そしてアクション定義を `handler` 関数に置くことができます。例えば:
```js
{
actions: {
someOtherAction ({dispatch}) {
dispatch('someAction')
}
},
modules: {
foo: {
namespaced: true,
actions: {
someAction: {
root: true,
handler (namespacedContext, payload) { ... } // -> 'someAction'
}
}
}
}
}
```
### 名前空間によるバインディングヘルパー
`mapState`、`mapGetters`、`mapActions`、そして `mapMutations` ヘルパーを使って名前空間付きモジュールをコンポーネントにバインディングするとき、少し冗長になります:
```js
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
}),
...mapGetters([
'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']
'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']
])
},
methods: {
...mapActions([
'some/nested/module/foo', // -> this['some/nested/module/foo']()
'some/nested/module/bar' // -> this['some/nested/module/bar']()
])
}
```
このような場合は、第1引数としてモジュールの名前空間文字列をヘルパーに渡すことで、そのモジュールをコンテキストとして使用してすべてのバインディングを行うことができます。上記は次のように単純化できます。
```js
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
}),
...mapGetters('some/nested/module', [
'someGetter', // -> this.someGetter
'someOtherGetter', // -> this.someOtherGetter
])
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
```
さらに、`createNamespacedHelpers` を使用することによって名前空間付けされたヘルパーを作成できます。指定された名前空間の値にバインドされた新しいコンポーネントバインディングヘルパーを持つオブジェクトを返します:
```js
import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
export default {
computed: {
// `some/nested/module` を調べます
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// `some/nested/module` を調べます
...mapActions([
'foo',
'bar'
])
}
}
```
### プラグイン開発者向けの注意事項
モジュールを提供する[プラグイン](plugins.md)を作成し、ユーザーがそれらを Vuex ストアに追加できるようにすると、モジュールの予測できない名前空間が気になるかもしれません。あなたのモジュールは、プラグインユーザーが名前空間付きモジュールの元にモジュールを追加すると、その名前空間に属するようになります。この状況に適応するには、プラグインオプションを使用して名前空間の値を受け取る必要があります。
```js
// プラグインオプションで名前空間値を取得し、
// そして、Vuex プラグイン関数を返す
export function createPlugin (options = {}) {
return function (store) {
// 名前空間をプラグインモジュールの型に追加する
const namespace = options.namespace || ''
store.dispatch(namespace + 'pluginAction')
}
}
```
## 動的にモジュールを登録する
ストアが作られた**後**に `store.registerModule` メソッドを使って、モジュールを登録できます:
```js
import { createStore } from 'vuex'
const store = createStore({ /* options */ })
// `myModule` モジュールを登録します
store.registerModule('myModule', {
// ...
})
// ネストされた `nested/myModule` モジュールを登録します
store.registerModule(['nested', 'myModule'], {
// ...
})
```
モジュールのステートには `store.state.myModule` と `store.state.nested.myModule` でアクセスします。
動的なモジュール登録があることで、他の Vue プラグインが、モジュールをアプリケーションのストアに付属させることで、状態の管理に Vuex を活用できます。例えば [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) ライブラリは、動的に付属させたモジュール内部でアプリケーションのルーティングのステートを管理することで vue-router と vuex を統合しています。
`store.unregisterModule(moduleName)` を呼び出せば、動的に登録したモジュールを削除できます。ただしストア作成(store creation)の際に宣言された、静的なモジュールはこのメソッドで削除できないことに注意してください。
また、すでにモジュールが登録されているかどうかを `store.hasModule(moduleName)` メソッドを使って確認することができます。 One thing to keep in mind is that nested modules should be passed as arrays for both the `registerModule` and `hasModule` and not as a string with the path to the module.
留意すべき点は、入れ子になっているモジュールは、`registerModule` と `hasModule` の両方に、モジュールへのパスを文字列として渡すのではなく、配列として渡す必要があるということです。
### ステートの保持
サーバサイドレンダリングされたアプリケーションから状態を保持するなど、新しいモジュールを登録するときに、以前の状態を保持したい場合があります。`preserveState` オプション(`store.registerModule('a', module, { preserveState: true })`)でこれを実現できます。
`preserveState: true` を設定した場合、モジュールを登録する際に、アクション、ミューテーション、そしてゲッターは追加されますがステートは追加されません。これはストアのステートはすでにモジュールのステートを登録しているので、それを上書きしないようにするためです。
## モジュールの再利用
時どき、モジュールの複数インスタンスを作成する必要があるかもしれません。例えば:
- 同じモジュールを使用する複数のストアを作成する(例: `runInNewContext` オプションが `false` または `'once'` のとき、[SSR でステートフルなシングルトンを避けるためです](https://ssr.vuejs.org/ja/structure.html#ステートフルなシングルトンの回避)。)
- 同じストアに同じモジュールを複数回登録する
モジュールの状態を宣言するために単純なオブジェクトを使用すると、その状態オブジェクトは参照によって共有され、変更時にクロスストア/モジュールの状態汚染を引き起こします。
これは、実際には Vue コンポーネント内部の `data` と全く同じ問題です。従って解決策も同じです。モジュールの状態を宣言するために関数を使用してください (2.3.0 以降でサポートされます):
```js
const MyReusableModule = {
state: () => ({
foo: 'bar'
}),
// ミューテーション、アクション、ゲッター...
}
```
================================================
FILE: docs/ja/guide/mutations.md
================================================
# ミューテーション
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/ckMZp4HN" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
実際に Vuex のストアの状態を変更できる唯一の方法は、ミューテーションをコミットすることです。Vuex のミューテーションはイベントにとても近い概念です: 各ミューテーションは**タイプ**と**ハンドラ**を持ちます。ハンドラ関数は Vuex の状態(state)を第1引数として取得し、実際に状態の変更を行います:
```js
const store = createStore({
state: {
count: 1
},
mutations: {
increment (state) {
// 状態を変更する
state.count++
}
}
})
```
直接ミューテーションハンドラを呼び出すことはできません。この mutations オプションは、どちらかいうと "タイプが `increment` のミューテーションがトリガーされたときに、このハンドラが呼ばれる" といったイベント登録のようなものです。ミューテーションハンドラを起動するためにはミューテーションのタイプを指定して `store.commit` を呼び出す必要があります:
```js
store.commit('increment')
```
## 追加の引数を渡してコミットする
`store.commit` に追加の引数を渡すこともできます。この追加の引数は、特定のミューテーションに対する**ペイロード**と呼びます:
```js
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
```
```js
store.commit('increment', 10)
```
ほとんどの場合、ペイロードはオブジェクトにすべきです。そうすることで複数のフィールドを含められるようになり、またミューテーションがより記述的に記録されるようになります:
```js
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
```
```js
store.commit('increment', {
amount: 10
})
```
## オブジェクトスタイルのコミット
また `type` プロパティを持つオブジェクトを使って、ミューテーションをコミットすることもできます:
```js
store.commit({
type: 'increment',
amount: 10
})
```
オブジェクトスタイルでコミットするとき、オブジェクト全体がペイロードとしてミューテーションハンドラに渡されます。したがってハンドラの例は上記と同じです:
```js
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
```
## ミューテーション・タイプに定数を使用する
いろいろな Flux 実装において、ミューテーション・タイプに定数を使用することが共通して見られるパターンです。これはコードに対してリントツールのようなツールを利用できるという利点があり、また単一ファイルに全ての定数を設定することによって、共同で作業する人に、アプリケーション全体で何のミューテーションが可能であるかを一目見ただけで理解できるようにします:
```js
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
```
```js
// store.js
import { createStore } from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = createStore({
state: { ... },
mutations: {
// 定数を関数名として使用できる ES2015 の算出プロパティ名(computed property name)機能を使用できます
[SOME_MUTATION] (state) {
// 状態を変更する
}
}
})
```
定数を使用するかどうかは好みの問題です。多くの開発者による大規模なプロジェクトで役に立ちますが、完全にオプションなので、もしお気に召さなければ使用しなくても構いません。
## ミューテーションは同期的でなければならない
ひとつの重要なルールを覚えておきましょう。それは**ミューテーションハンドラ関数は同期的でなければならない**ということです。なぜか?次の例で考えてみましょう:
```js
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
```
いま、開発ツールのミューテーションのログを見ながら、アプリケーションのデバッグを行っていることを想像してください。全てのミューテーションをログに記録するためには、ミューテーションの前後の状態のスナップショットを捕捉することが必要です。しかし、上の例にあるミューテーション内の非同期コールバックは、それを不可能にします: そのコールバックは、ミューテーションがコミットされた時点ではまだ呼び出されていません。そして、コールバックが実際にいつ呼び出されるかを、開発ツールは知る術がありません。いかなる状態変更でも、コールバック内で起きる場合は本質的に追跡不可能です。
## コンポーネント内におけるミューテーションのコミット
`this.$store.commit('xxx')` と書くか、もしくはコンポーネントのメソッドを `store.commit` にマッピングする `mapMutations` ヘルパーを呼び出すこと(ルートの `store` の注入が必要)で、コンポーネント内でミューテーションをコミットできます:
```js
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // `this.increment()` を `this.$store.commit('increment')` にマッピングする
// mapMutations はペイロードサポートする:
'incrementBy' // `this.incrementBy(amount)` を `this.$store.commit('incrementBy', amount)` にマッピングする
]),
...mapMutations({
add: 'increment' // `this.add()` を `this.$store.commit('increment')` にマッピングする
})
}
}
```
## アクションへ向けて
状態変更を非同期に組み合わせることは、プログラムの動きを予測することを非常に困難にします。例えば、状態を変更する非同期コールバックを持った 2つのメソッドを両方呼び出すとき、それらがいつ呼び出されたか、どちらが先に呼び出されたかを、どうやって知ればよいのでしょう?これがまさに、状態変更と非同期の 2つの概念を分離したいという理由です。Vuex では**全てのミューテーションは同期的に行う**という作法になっています:
```js
store.commit('increment')
// "increment" ミューテーションによる状態変更は、この時点で行われるべきです
```
非同期的な命令を扱うために[アクション](actions.md)を見てみましょう。
================================================
FILE: docs/ja/guide/plugins.md
================================================
# プラグイン
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cvp8ZkCR" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
Vuex ストア は、各ミューテーションへのフックを公開する `plugins` オプションを受け付けます。 Vuex プラグインは、単一の引数としてストアを受けつけるただの関数です:
```js
const myPlugin = (store) => {
// ストアが初期化されたときに呼ばれます
store.subscribe((mutation, state) => {
// それぞれのミューテーションの後に呼ばれます
// ミューテーションは `{ type, payload }` の形式で提供されます
})
}
```
そして、このように利用することができます:
```js
const store = createStore({
// ...
plugins: [myPlugin]
})
```
## プラグイン内でのミューテーションのコミット
プラグインは直接、状態を変更できません。これはコンポーネントに似ています。プラグインはコンポーネント同様に、ミューテーションのコミットをトリガーすることで状態を変更できます。
ミューテーションのコミットによるストアとデータソースの同期をプラグインで実現できます。 websocket データソースとストアを例にします (これは不自然で作為的な例です。実際には `createWebSocketPlugin` 関数は、さらに複雑なタスクのために追加でいくつかのオプションを受け取れます):
```js
export default function createWebSocketPlugin (socket) {
return (store) => {
socket.on('data', data => {
store.commit('receiveData', data)
})
store.subscribe(mutation => {
if (mutation.type === 'UPDATE_DATA') {
socket.emit('update', mutation.payload)
}
})
}
}
```
```js
const plugin = createWebSocketPlugin(socket)
const store = createStore({
state,
mutations,
plugins: [plugin]
})
```
## 状態のスナップショットを撮る
時々、状態の"スナップショット"を撮って、ミューテーション前後の状態を比較したくなることがあるでしょう。それを実現するために、状態オブジェクトのディープコピーを行う必要があります:
```js
const myPluginWithSnapshot = (store) => {
let prevState = _.cloneDeep(store.state)
store.subscribe((mutation, state) => {
let nextState = _.cloneDeep(state)
// `prevState` と `nextState` を比較...
// 次のミューテーションのために状態を保存
prevState = nextState
})
}
```
**状態のスナップショットを撮るプラグインはアプリケーションの開発の間だけ使われるべきです。** webpack や Browserify を使っていれば、ビルドツールにそれを処理させることができます:
```js
const store = createStore({
// ...
plugins: process.env.NODE_ENV !== 'production'
? [myPluginWithSnapshot]
: []
})
```
上のように記述すれば、プラグインはデフォルトで利用されることになります。本番環境( production ) では、 `process.env.NODE_ENV !== 'production'` を `false` に置き換えるために、 webpack では[DefinePlugin](https://webpack.js.org/plugins/define-plugin/) 、 Browserify では[envify](https://github.com/hughsk/envify) が必要になります。
## ビルトインロガープラグイン
Vuex には、一般的なデバッグに利用する用途の備え付けのロガープラグインがあります。
```js
import { createLogger } from 'vuex'
const store = createStore({
plugins: [createLogger()]
})
```
`createLogger` 関数はいくつかのオプションを受け取ります:
```js
const logger = createLogger({
collapsed: false, // ログ出力されたミューテーションを自動で展開します
filter (mutation, stateBefore, stateAfter) {
// ミューテーションを記録する必要がある場合は、`true` を返します
// `mutation` は `{ type, payload }` です
return mutation.type !== "aBlocklistedMutation"
},
actionFilter (action, state) {
// `filter` と同等ですが、アクション用です
// `action` は `{ type, payloed }` です
return action.type !== "aBlocklistedAction"
},
transformer (state) {
// ロギングの前に、状態を変換します
// 例えば、特定のサブツリーのみを返します
return state.subTree
},
mutationTransformer (mutation) {
// ミューテーションは、`{ type, payload }` の形式でログ出力されます
// 任意の方法でそれをフォーマットできます
return mutation.type
},
actionTransformer (action) {
// `mutationTransformer` と同等ですが、アクション用です
return action.type
},
logActions: true, // アクションログを出力します。
logMutations: true, // ミューテーションログを出力します。
logger: console, // `console` API の実装, デフォルトは `console`
})
```
ロガーファイルは、他にも `<script>` タグで直接読み込むことができ、`createVuexLogger` 関数がグローバルに公開されます。
ロガープラグインは、状態のスナップショットを撮ることに注意しましょう。スナップショットを撮ることはコストがかかるため、開発中だけ利用してください。
================================================
FILE: docs/ja/guide/state.md
================================================
# ステート
## 単一ステートツリー
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cWw3Zhb" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
Vuex は **単一ステートツリー (single state tree)** を使います。つまり、この単一なオブジェクトはアプリケーションレベルの状態が全て含まれており、"信頼できる唯一の情報源 (single source of truth)" として機能します。これは、通常、アプリケーションごとに1つしかストアは持たないことを意味します。単一ステートツリーは状態の特定の部分を見つけること、デバッグのために現在のアプリケーションの状態のスナップショットを撮ることを容易にします。
単一ステートツリーはモジュール性と競合しません。以降の章で、アプリケーションの状態とミューテーション(変更)をサブモジュールに分割する方法について説明します。
Vuexに保存するデータは、Vueインスタンスの `data` と同じルールに従います。つまり、ステートオブジェクトはプレーンでなければなりません。[Vue#data](https://v3.ja.vuejs.org/api/options-data.html#data-2)も参照してください。
## Vuex の状態を Vue コンポーネントに入れる
ストアにある状態を Vue コンポーネント に表示するにはどうすればよいのでしょう? Vuex ストア はリアクティブなので、ストアから状態を"取り出す"一番シンプルな方法は、単純にいくつかのストアの状態を [算出プロパティ](https://jp.vuejs.org/guide/computed.html) で返すことです。
```js
// Counter コンポーネントをつくってみましょう
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count
}
}
}
```
`store.state.count` が変わるたび、算出プロパティの再評価が発生し、関連した DOM の更新をトリガーします。
しかし、このパターンでは、コンポーネントがグローバルストアシングルトンに依存してしまいます。 モジュールシステムを使っているとき、ストアの状態を使っているすべてのコンポーネントでインポートが必要です。また、コンポーネントのテストのときにモック化が必要となります。
Vuex は Vue のプラグインシステムを通じて、ルートコンポーネントからすべての子コンポーネントにストアを "注入" し、それらのコンポーネントでは `this.$store` として利用できるようになります。それでは `Counter` の実装を変更しましょう:
```js
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
```
## `mapState` ヘルパー
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c8Pz7BSK" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
コンポーネントが複数のストアのステートプロパティやゲッターを必要としているとき、これらすべてにおいて、算出プロパティを宣言することは繰り返しで冗長です。これに対処するため、算出ゲッター関数を生成し、いくつかのキーストロークを省くのに役立つ `mapState` ヘルパーを使うことができます:
```js
// 完全ビルドでは、ヘルパーは Vuex.mapState として公開されています
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// アロー関数は、コードをとても簡潔にできます!
count: state => state.count,
// 文字列を渡すことは、`state => state.count` と同じです
countAlias: 'count',
// `this` からローカルステートを参照するときは、通常の関数を使わなければいけません
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
```
マップされた算出プロパティの名前がステートサブツリーの名前と同じ場合は、文字列配列を `mapState` に渡すこともできます。
```js
computed: mapState([
// map this.count to store.state.count
'count'
])
```
## オブジェクトスプレッド演算子
`mapState` はオブジェクトを返すことに注意しましょう。どうやって、他のローカル算出プロパティと組み合わせるのでしょうか? 通常、最終的にひとつのオブジェクトを `computed` に渡せるように、複数のオブジェクトをひとつにマージするユーティリティを使わなければいけません。しかし、[オブジェクトスプレッド演算子](https://github.com/tc39/proposal-object-rest-spread)で、シンタックスをかなり単純にできます:
```js
computed: {
localComputed () { /* ... */ },
// オブジェクトスプレット演算子で、外のオブジェクトとこのオブジェクトを混ぜる
...mapState({
// ...
})
}
```
## コンポーネントはまだローカルステートを持つことできる
Vuex を使うということは、**全て**の状態を Vuex の中に置くべき、というわけではありません。多くの状態を Vuex に置くことで、状態の変更がさらに明示的、デバッグ可能になりますが、ときにはコードを冗長でまわりくどいものにします。状態の一部がひとつのコンポーネントだけに属している場合は、それをローカルの状態として残しておくとよいでしょう。あなたは、トレードオフを考慮した上で、あなたのアプリの開発ニーズに合った決定をすべきです。
================================================
FILE: docs/ja/guide/strict.md
================================================
# 厳格モード
厳格(strict)モードを有効にするには Vuex store を作成するときに、ただ `strict: true` を指定するだけです:
```js
const store = createStore({
// ...
strict: true
})
```
厳格モードでは Vuex の状態がミューテーションハンドラの外部で変更されたら、エラーを投げるようになります。これで全ての状態変更がデバッギングツールで明示的に追跡できることが保証されます。
## 開発環境 vs 本番環境
**本番環境で厳格モードを有効にしてデプロイしてはいけません!** 厳格モードでは不適切なミューテーションを検出するためにステートツリーに対して深い監視を実行します。パフォーマンスコストを回避するために本番環境では無効にしてください。
プラグインと同様に、ビルドツールに処理させることができます:
```js
const store = createStore({
// ...
strict: process.env.NODE_ENV !== 'production'
})
```
================================================
FILE: docs/ja/guide/structure.md
================================================
# アプリケーションの構造
Vuex は実際のところ、あなたがコードを構造化する方法を制限しません。もっと正確に言うと、それより高いレベルの原理原則を適用させます:
1. アプリケーションレベルの状態はストアに集約されます。
2. 状態を変更する唯一の方法は、同期的に処理を行う**ミューテーション**をコミットすることのみです。
3. 非同期的なロジックはカプセル化されるべきであり、それは**アクション**によって構成されます。
これらのルールに従っている限り、プロジェクトをどのように構造化するかはあなた次第です。もしストアファイルが大きくなり過ぎたら、単純にアクションやミューテーション、ゲッターをそれぞれ別のファイルに切り出すことができます。
それなりに手の込んだアプリケーションであれば、モジュールを活用する必要が出てきそうです。プロジェクトの構造の例は以下のようになります:
```bash
├── index.html
├── main.js
├── api
│ └── ... # API 呼び出しを抽象化する
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # モジュールを集めてストアをエクスポートする
├── actions.js # アクションのルートファイル
├── mutations.js # ミューテーションのルートファイル
└── modules
├── cart.js # cart モジュール
└── products.js # products モジュール
```
参考として [Shopping Cart Example](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart) をみてみるのもよいでしょう。
================================================
FILE: docs/ja/guide/testing.md
================================================
# テスト
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/cPGkpJhq" target="_blank" rel="noopener noreferrer">Scrimba のレッスンを試す</a></div>
私たちが Vuex でユニットテストしたい主な部分はミューテーションとアクションです。
## ミューテーションのテスト
ミューテーションは完全に引数に依存しているだけの関数であるため、テストするのがとても簡単です。効果的なやり方として、もし ES2015 のモジュールを使っていて `store.js` ファイルの中にミューテーションがあるなら、デフォルトエクスポートに加えて、名前付きエクスポートでミューテーションをエクスポートできます。
```js
const state = { ... }
// 名前付きエクスポートでミューテーションをエクスポートする
export const mutations = { ... }
export default createStore({
state,
mutations
})
```
Mocha + Chai を使用してミューテーションをテストする例です(あなたの好きな任意のフレームワーク/アサーションライブラリを使用できます):
```js
// mutations.js
export const mutations = {
increment: state => state.count++
}
```
```js
// mutations.spec.js
import { expect } from 'chai'
import { mutations } from './store'
// ミューテーションの分割束縛
const { increment } = mutations
describe('mutations', () => {
it('INCREMENT', () => {
// ステートのモック
const state = { count: 0 }
// ミューテーションを適用する
increment(state)
// 結果を検証する
expect(state.count).to.equal(1)
})
})
```
## アクションのテスト
アクションは外部の API を呼び出す可能性があるため、ミューテーションのテストよりも少し注意が必要です。アクションをテストするとき、通常、いくつかの段階でモックを作る必要があります。例えば API 呼び出しをサービスとして抽象化し、そしてテストの内部ではそのサービスをモックにすることができます。簡単に依存関係をモック化するために、webpack と [inject-loader](https://github.com/plasticine/inject-loader) を使ってテストファイルをバンドルすることができます。
非同期なアクションのテストの例:
```js
// actions.js
import shop from '../api/shop'
export const getAllProducts = ({ commit }) => {
commit('REQUEST_PRODUCTS')
shop.getProducts(products => {
commit('RECEIVE_PRODUCTS', products)
})
}
```
```js
// actions.spec.js
// inline loader のために require 構文を使用する
// ここでは inject-loader を使って、モック化された依存関係を注入できるようにするモジュールファクトリーを返す
import { expect } from 'chai'
const actionsInjector = require('inject-loader!./actions')
// モックによってモジュールを作成する
const actions = actionsInjector({
'../api/shop': {
getProducts (cb) {
setTimeout(() => {
cb([ /* レスポンスのモック */ ])
}, 100)
}
}
})
// 期待されるミューテーションをアクションが呼び出すかをテストするためのヘルパー
const testAction = (action, payload, state, expectedMutations, done) => {
let count = 0
// コミットをモックする
const commit = (type, payload) => {
const mutation = expectedMutations[count]
try {
expect(type).to.equal(mutation.type)
expect(payload).to.deep.equal(mutation.payload)
} catch (error) {
done(error)
}
count++
if (count >= expectedMutations.length) {
done()
}
}
// モック化したストアと引数でアクションを呼び出す
action({ commit, state }, payload)
// 呼び出されるべきミューテーションが残っていないか確認する
if (expectedMutations.length === 0) {
expect(count).to.equal(0)
done()
}
}
describe('actions', () => {
it('getAllProducts', done => {
testAction(actions.getAllProducts, null, {}, [
{ type: 'REQUEST_PRODUCTS' },
{ type: 'RECEIVE_PRODUCTS', payload: { /* レスポンスのモック */ } }
], done)
})
})
```
テスト環境において利用可能なスパイがあるのなら(例えば[Sinon.JS](http://sinonjs.org/))、`testAction` ヘルパーの代わりにそれらを使用できます:
```js
describe('actions', () => {
it('getAllProducts', () => {
const commit = sinon.spy()
const state = {}
actions.getAllProducts({ commit, state })
expect(commit.args).to.deep.equal([
['REQUEST_PRODUCTS'],
['RECEIVE_PRODUCTS', { /* レスポンスのモック */ }]
])
})
})
```
## ゲッターのテスト
もしゲッターが複雑な計算を行っているならば、テストコードを書く価値があります。ゲッターはミューテーションと同様の理由でテストしやすいです。
ゲッターのテストの例:
```js
// getters.js
export const getters = {
filteredProducts (state, { filterCategory }) {
return state.products.filter(product => {
return product.category === filterCategory
})
}
}
```
```js
// getters.spec.js
import { expect } from 'chai'
import { getters } from './getters'
describe('getters', () => {
it('filteredProducts', () => {
// ステートをモックする
const state = {
products: [
{ id: 1, title: 'Apple', category: 'fruit' },
{ id: 2, title: 'Orange', category: 'fruit' },
{ id: 3, title: 'Carrot', category: 'vegetable' }
]
}
// ゲッターをモックする
const filterCategory = 'fruit'
// ゲッターから結果を受け取る
const result = getters.filteredProducts(state, { filterCategory })
// 結果を検証する
expect(result).to.deep.equal([
{ id: 1, title: 'Apple', category: 'fruit' },
{ id: 2, title: 'Orange', category: 'fruit' }
])
})
})
```
## テストの実行
ミューテーションやアクションが適切に書かれている場合は、適切にモック化された後、テストコードはブラウザの API に直接依存関係を持つことはないでしょう。したがって、単純に webpack でテストをバンドルでき、それを直接 Node で実行できます。別の方法として、本当のブラウザでテストを実行するためには `mocha-loader` または Karma + `karma-webpack` を使用できます。
### Node での実行
以下のような webpack の設定を作成します([`.babelrc`](https://babeljs.io/docs/usage/babelrc/) もあわせて使います):
```js
// webpack.config.js
module.exports = {
entry: './test.js',
output: {
path: __dirname,
filename: 'test-bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
}
}
```
それから下記コマンドを実行します:
``` bash
webpack
mocha test-bundle.js
```
### ブラウザでの実行
1. `mocha-loader` をインストールする
2. 上記 webpack 設定から `entry` を `'mocha-loader!babel-loader!./test.js'` に変更する
3. 設定を使用して `webpack-dev-server` を開始する
4. ブラウザで `localhost:8080/webpack-dev-server/test-bundle` を開く
### Karma + karma-webpack を使ったブラウザでの実行
[vue-loader ドキュメント](https://vue-loader.vuejs.org/ja/workflow/testing.html) 内のセットアップ方法を参考にしてください。
================================================
FILE: docs/ja/guide/typescript-support.md
================================================
# TypeScript サポート
Vuex は型付けを提供しているので、TypeScript を使ってストア定義を書くことができます。Vuex には特別な TypeScript の設定は必要ありません。[Vue の基本的な TypeScript の設定](https://v3.ja.vuejs.org/guide/typescript-support.html) に従ってプロジェクトの設定を行ってください。
しかし、Vue コンポーネントを TypeScript で書いている場合は、ストアの型付けを正しく行うために必要な手順がいくつかあります。
## Vue コンポーネントでの `$store` プロパティの型付け
Vuex はすぐに使用できる `this.$store` プロパティの型付けを提供していません。TypeScriptと併用する場合は、独自のモジュール拡張を宣言する必要があります。
プロジェクトフォルダに宣言ファイルを追加して、Vue の `ComponentCustomProperties` のカスタム型付けを宣言します。
```ts
// vuex.d.ts
import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'
declare module 'vue' {
// ストアのステートを宣言する
interface State {
count: number
}
// `this.$store` の型付けを提供する
interface ComponentCustomProperties {
$store: Store<State>
}
}
```
## `useStore` 関数の型付け
Composition API で Vue コンポーネントを記述する際には、ほとんどの場合、`useStore`が型付けされたストアを返すようにしたいでしょう。`useStore` が正しく型付けされたストアを返すためには次のことが必要です。
1. 型付けされた `InjectionKey` を定義する。
2. ストアをインストールする際に、型付けされた `InjectionKey` を Vue App インスタンスに渡す。
3. 型付けされた `InjectionKey` を `useStore` メソッドに渡す。
それでは、順を追って説明していきます。まずは、Vue の `InjectionKey` インターフェースを使って独自のストアの型定義とともにキーを定義します。
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
// ストアのステートに対して型を定義します
export interface State {
count: number
}
// インジェクションキーを定義します
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
```
次に、ストアのインストール時に定義した `InjectionKey` を Vue App インスタンスに渡します。
```ts
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
// pass the injection key
app.use(store, key)
app.mount('#app')
```
最後に、このキーを `useStore` メソッドに渡すことで型付けされたストアを取得することができます。
```ts
// in a vue component
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // typed as number
}
}
```
内部的には、Vuex は Vue の [Provide/Inject](https://v3.ja.vuejs.org/api/composition-api.html#provide-inject) 機能を使って Vue App インスタンスにストアをインストールします。これが、 `InjectionKey` によって型定義を提供できる理由です。
### `useStore` 使用方法の簡略化
`useStore` 関数を使うたびに `InjectionKey` をインポートして、 `useStore` へ渡さなければならないのは少し面倒かもしれません。その場合、型付けされたストアを取得する独自の関数を定義すると良いでしょう。
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
export interface State {
count: number
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
// 独自の `useStore` 関数を定義します
export function useStore () {
return baseUseStore(key)
}
```
この関数を使用することで、 `InjectionKey` とその型を提供しなくても、型付けされたストアを取得することができます。
```ts
// vue component 内
import { useStore } from './store'
export default {
setup () {
const store = useStore()
store.state.count // number として型付け
}
}
```
================================================
FILE: docs/ja/index.md
================================================
# Vuex とは何か?
::: tip 注意
これは、Vue 3 で動作する Vuex 4 のためのドキュメントです。Vue 2 で動作する Vuex 3 のドキュメントをお探しの方は、[こちらをご覧ください](https://vuex.vuejs.org/ja/)。
:::
Vuex は Vue.js アプリケーションのための **状態管理パターン + ライブラリ**です。
これは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。
## "状態管理パターン"とはなんですか?
単純な Vue で作られたカウンターアプリをみてみましょう:
```js
const Counter = {
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
}
createApp(Counter).mount('#app')
```
これはいくつかの要素をアプリ自身に含んでいます:
- **状態**、これは私達のアプリを動かす信頼できる情報源(the source of truth)です。
- **ビュー**、これは**状態**のただの宣言的なマッピングです。
- **アクション**、これは**ビュー**からのユーザー入力に反応して、状態の変更を可能にする方法です。
これらは"単方向データフロー"のコンセプトの極めてシンプルな責務です:
<p style="text-align: center; margin: 2em">
<img style="width:100%; max-width:450px;" src="/flow.png">
</p>
しかし、単純さは、**共通の状態を共有する複数のコンポーネントを持ったときに**、すぐに破綻します:
- 複数のビューが同じ状態に依存することがあります。
- 異なるビューからのアクションで、同じ状態を変更する必要があります。
一つ目は、プロパティ (props) として深く入れ子になったコンポーネントに渡すのは面倒で、兄弟コンポーネントでは単純に機能しません。二つ目は、親子のインスタンスを直接参照したり、イベントを介して複数の状態のコピーを変更、同期することを試みるソリューションに頼っていることがよくあります。これらのパターンは、いずれも脆く、すぐにメンテナンスが困難なコードに繋がります。
では、コンポーネントから共有している状態を抽出し、それをグローバルシングルトンで管理するのはどうでしょうか? これにより、コンポーネントツリーは大きな "ビュー" となり、どのコンポーネントもツリー内のどこにあっても状態にアクセスしたり、アクションをトリガーできます!
さらに、状態管理に関わる概念を定義、分離し、特定のルールを敷くことで、コードの構造と保守性を向上させることができます。
これが Vuex の背景にある基本的なアイディアであり、[Flux](https://facebook.github.io/flux/docs/overview)、 [Redux](http://redux.js.org/) そして [The Elm Architecture](https://guide.elm-lang.org/architecture/)から影響を受けています。
他のパターンと異なるのは、Vuex は効率的な更新のために、Vue.js の粒度の細かいリアクティビティシステムを利用するよう特別に調整して実装されたライブラリだということです。
あなたがもし対話型の方法でVuexを学びたいのであれば、[Scrimba](https://scrimba.com/g/gvuex)のVuexコースをぜひ試してみてください。

## いつ、Vuexを使うべきでしょうか?
Vuex は、共有状態の管理に役立ちますが、さらに概念やボイラープレートのコストがかかります。これは、短期的生産性と長期的生産性のトレードオフです。
もし、あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で気が遠くなるように感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。単純な [ストアパターン](https://v3.ja.vuejs.org/guide/state-management.html#simple-state-management-from-scratch) が必要なだけかもしれません。しかし、今あなたが中規模から大規模の SPA を構築しているなら、Vue コンポーネントの外の状態をもっとうまく扱えないか考えなくてはならない状況にあるかもしれません。その場合 Vuex は次のステップとして最適でしょう。これは Redux の作者、Dan Abramov からの良い引用です:
> Flux ライブラリは眼鏡のようなものです: あなたが必要な時にいつでも分かるのです。
================================================
FILE: docs/ja/installation.md
================================================
# インストール
## 直接ダウンロードする / CDN
[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)
<!--email_off-->
[Unpkg.com](https://unpkg.com) で NPM ベースの CDN リンクが提供されています。上記リンクは常に NPM の最新のリリースを指します。`https://unpkg.com/vuex@4.0.0/dist/vuex.global.js` のような URL によって特定のバージョン/タグを利用することもできます。
<!--/email_off-->
Vue のあとで `vuex` を取り込むと自動的に Vuex が導入されます:
```html
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
```
## NPM
```bash
npm install vuex@next --save
```
## Yarn
```bash
yarn add vuex@next --save
```
## 開発版ビルド
最新の開発版ビルドを利用したい場合には、 GitHub から直接クローンし `vuex` を自身でビルドする必要があります。
```bash
git clone https://github.com/vuejs/vuex.git node_modules/vuex
cd node_modules/vuex
yarn
yarn build
```
================================================
FILE: docs/ptbr/api/index.md
================================================
---
sidebar: auto
---
# Referência da API
## Store
### createStore
- `createStore<S>(options: StoreOptions<S>): Store<S>`
Cria um novo _store_.
```js
import { createStore } from 'vuex'
const store = createStore({ ...options })
```
## Opções do Construtor Store
### state (estado)
- type: `Object | Function`
O objeto raiz de estado para o _store_ Vuex. [Detalhes](../guide/state.md)
Se você passar uma função que retorna um objeto, o objeto retornado é usado como o estado raiz. Isso é útil quando você deseja reutilizar o objeto de estado, especialmente para reutilização de módulos. [Detalhes](../guide/modules.md#reutilizacao-do-modulo)
### mutations (mutações)
- type: `{ [type: string]: Function }`
Registra mutações no _store_. A função manipuladora (ou _handler_) sempre recebe _state_ como o 1º argumento (será o estado local do módulo se definido em um módulo) e receberá um 2º argumento _payload_ se houver um.
[Detalhes](../guide/mutations.md)
### actions (ações)
- type: `{ [type: string]: Function }`
Registra ações no _store_. A função manipuladora (ou _handler_) recebe um objeto _context_ que expõe as seguintes propriedades:
```js
{
state, // o mesmo que `store.state`, ou estado local se estiver em módulos
rootState, // o mesmo que `store.state`, apenas em módulos
commit, // o mesmo que `store.commit`
dispatch, // o mesmo que `store.dispatch`
getters, // o mesmo que `store.getters`, ou getters locais se estiver em módulos
rootGetters // o mesmo que `store.getters`, apenas em módulos
}
```
E também recebe um 2º argumento _payload_ se houver um.
[Detalhes](../guide/actions.md)
### getters
- type: `{ [key: string]: Function }`
Registra os _getters_ no _store_. A função _getter_ recebe os seguintes argumentos:
```
state, // será estado local do módulo se definido em um módulo.
getters // o mesmo que store.getters
```
Especificamente quando definido em um módulo
```
state, // será estado local do módulo se definido em um módulo.
getters, // módulo de getters locais do módulo atual.
rootState, // estado global
rootGetters // todos os getters
```
Os _getters_ registrados estão expostos em `store.getters`.
[Detalhes](../guide/getters.md)
### modules (módulos)
- type: `Object`
Um objeto contendo sub módulos a serem incorporados no _store_, de forma que:
```js
{
key: {
state,
namespaced?,
mutations?,
actions?,
getters?,
modules?
},
...
}
```
Cada módulo pode conter _state_ e _mutations_ semelhantes às opções raiz. O estado de um módulo será anexado ao estado da raiz do _store_ usando a chave do módulo. As mutações e _getters_ de um módulo receberão apenas o estado local do módulo como o 1º argumento em vez do estado da raiz, e as ações do módulo _context.state_ também apontarão para o estado local.
[Detalhes](../guide/modules.md)
### plugins
- type: `Array<Function>`
Um _Array_ de funções de plug-in a serem aplicadas no _store_. O plug-in simplesmente recebe o _store_ como o único argumento e pode ouvir mutações (para persistência de dados de saída, registro ou depuração) ou despachar mutações (para dados de entrada, por exemplo, _websockets_ ou _observables_).
[Detalhes](../guide/plugins.md)
### strict
- type: `boolean`
- default: `false`
Força o _store_ Vuex a rodar mo modo estrito. No modo estrito, qualquer mutação ao estado do Vuex fora dos manipuladores de mutação acusará um erro.
[Detalhes](../guide/strict.md)
### devtools
- type: `boolean`
Ative ou desative o _devtools_ para uma determinada instância Vuex. Passar `false` à instância diz ao _store_ Vuex para não se integrar ao _devtools_. Bem útil quando se tem vários _stores_ em uma _single_ _page_.
```js
{
devtools: false
}
```
## Propriedades da Instância Store
### state (estado)
- type: `Object`
O estado raiz. Apenas leitura.
### getters
- type: `Object`
Expõe os _getters_ registrados. Apenas leitura.
## Métodos da Instância Store
### commit
- `commit(type: string, payload?: any, options?: Object)`
- `commit(mutation: Object, options?: Object)`
Confirma (ou faz um _Commit_ de) uma mutação. _options_ pode ter `root: true` que permite confirmar mutações da raiz em [módulos namespaced](../guide/modules.md#namespacing). [Detalhes](../guide/mutations.md)
### dispatch
- `dispatch(type: string, payload?: any, options?: Object): Promise<any>`
- `dispatch(action: Object, options?: Object): Promise<any>`
Despacha uma ação. _options_ pode ter `root: true` que permite despachar ações para raiz em [módulos namespaced](../guide/modules.md#namespacing). Retorna um _Promise_ que resolve todos os manipuladores de ação acionados. [Detalhes](../guide/actions.md)
### replaceState
- `replaceState(state: Object)`
Substitue o estado da raiz do _store_. Use isso apenas para fins de _hydration_ / _time-travel_.
### watch
- `watch(fn: Function, callback: Function, options?: Object): Function`
Visualiza de forma reativa um valor de retorno de `fn`, e chama o _callback_ para o retorno de chamada quando o valor for alterado. O `fn` recebe o estado do _store_ como o 1º argumento, e os _getters_ como o 2º argumento. Aceita um objeto de opções opcional que leva as mesmas opções que o [método vm.$watch do Vue](https://vuejs.org/v2/api/#vm-watch).
Para parar um _watch_, chame a função _unwatch_ retornada.
### subscribe
- `subscribe(handler: Function, options?: Object): Function`
Assinatura para as mutações do _store_. O `manipulador` é chamado após cada mutação e recebe o descritor da mutação e o estado pós-mutação como argumentos:
```js
const unsubscribe = store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
// you may call unsubscribe to stop the subscription
unsubscribe()
```
Por padrão, o novo manipulador é adicionado ao final da cadeia, então ele será executado após outros manipuladores que foram adicionados antes. Isso pode ser sobrescrito adicionando `prepend: true` a _options_, que irá adicionar o manipulador ao início da cadeia.
```js
store.subscribe(handler, { prepend: true })
```
O método _subscribe_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, você pode assinar um Módulo Vuex e cancelar a assinatura ao cancelar o registro do módulo. Ou você pode chamar _subscribe_ de dentro de um componente Vue e então destruir o componente mais tarde. Nesses casos, você deve se lembrar de cancelar a assinatura manualmente.
Mais comumente usado em plugins. [Detalhes](../guide/plugins.md)
### subscribeAction
- `subscribeAction(handler: Function, options?: Object): Function`
Assinatura para as ações do _store_. O `manipulador` é chamado para cada ação despachada e recebe o descritor da ação e o estado de armazenamento atual como argumentos.
O método _subscribe_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, ao cancelar o registro de um módulo Vuex ou antes de destruir um componente Vue.
```js
const unsubscribe = store.subscribeAction((action, state) => {
console.log(action.type)
console.log(action.payload)
})
// you may call unsubscribe to stop the subscription
unsubscribe()
```
Por padrão, o novo manipulador é adicionado ao final da cadeia, então ele será executado após outros manipuladores que foram adicionados antes. Isso pode ser sobrescrito adicionando `prepend: true` a _options_, que irá adicionar o manipulador ao início da cadeia.
```js
store.subscribeAction(handler, { prepend: true })
```
O método _subscribeAction_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, você pode assinar um Módulo Vuex e cancelar a assinatura ao cancelar o registro do módulo. Ou você pode chamar _subscribeAction_ de dentro de um componente Vue e então destruir o componente mais tarde. Nesses casos, você deve se lembrar de cancelar a assinatura manualmente.
_subscribeAction_ também pode especificar se a função manipuladora da assinatura deve ser chamada *antes* ou *depois* de um despacho de ação (o comportamento padrão é *antes*):
```js
store.subscribeAction({
before: (action, state) => {
console.log(`before action ${action.type}`)
},
after: (action, state) => {
console.log(`after action ${action.type}`)
}
})
```
_subscribeAction_ também pode especificar uma função manipuladora _error_ para capturar um erro lançado quando uma ação é despachada. A função receberá um objeto _error_ como 3º argumento.
```js
store.subscribeAction({
error: (action, state, error) => {
console.log(`error action ${action.type}`)
console.error(error)
}
})
```
O método _subscribeAction_ é mais comumente usado em plugins. [Detalhes](../guide/plugins.md)
### registerModule
- `registerModule(path: string | Array<string>, module: Module, options?: Object)`
Registra um módulo dinâmico. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)
_options_ podem ter `preserveState: true` que permite preservar o estado anterior. Bem útil quando fazemos renderização do lado do servidor (_server-side-rendering_).
### unregisterModule
- `unregisterModule(path: string | Array<string>)`
Cancela o registro de um módulo dinâmico. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)
### hasModule
- `hasModule(path: string | Array<string>): boolean`
Verifica se o módulo com o nome fornecido já foi registrado. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)
### hotUpdate
- `hotUpdate(newOptions: Object)`
Faz _hot_ _swap_ de novas ações e mutações [Detalhes](../guide/hot-reload.md)
## Métodos Auxiliares de Vinculação aos Componentes
### mapState
- `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`
Cria dados computados do componente que retornam a subárvore do _store_ Vuex. [Detalhes](../guide/state.md#o-auxiliar-mapstate)
O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)
O segundo objeto que compõem os argumentos pode ser uma função. `function(state: any)`
### mapGetters
- `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`
Cria dados computados do componente que retornam o valor calculado de um _getter_. [Detalhes](../guide/getters.md#o-auxiliar-mapgetters)
O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)
### mapActions
- `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`
Cria opções de métodos nos componentes que despacham uma ação. [Detalhes](../guide/actions.md#despachando-acoes-em-componentes)
O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)
O segundo objeto que compõem os argumentos pode ser uma função. `function(dispatch: function, ...args: any[])`
### mapMutations
- `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`
Cria opções de métodos nos componentes que confirmam (ou fazem um _commit_ de) uma mutação. [Detalhes](../guide/mutations.md#confirmando-ou-fazendo-commits-de-mutacoes-em-componentes)
O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)
O segundo objeto que compõem os argumentos pode ser uma função. `function(commit: function, ...args: any[])`
### createNamespacedHelpers
- `createNamespacedHelpers(namespace: string): Object`
Cria métodos auxiliares de componentes vinculados por um nome. O objeto retornado conterá `mapState`, `mapGetters`, `mapActions` e `mapMutations`, que estão vinculados ao _namespace_ fornecido. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)
## Funções de Composição
### useStore
- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`
Busca o _store_ injetado quando chamado dentro do gatilho (ou _hook_) _setup_. Ao usar a API de composição, você pode recuperar o _store_ chamando este método.
```js
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
```
Os usuários do TypeScript podem usar uma _injection_ _key_ para recuperar um _store_ tipado. Para que isso funcione, você deve definir a _injection_ _key_ e passá-la junto com o _store_ ao instalar a instância do _store_ na aplicação Vue.
Primeiro, declare a _injection_ _key_ usando a interface `InjectionKey` do Vue.
```ts
// store.ts
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
export interface State {
count: number
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store = createStore<State>({
state: {
count: 0
}
})
```
Então, passe a _key_ definida como o 2º argumento para o método `app.use`.
```ts
// main.ts
import { createApp } from 'vue'
import { store, key } from './store'
const app = createApp({ ... })
app.use(store, key)
app.mount('#app')
```
Finalmente, você pode passar a _key_ para o método _useStore_ para recuperar a instância tipada do _store_.
```ts
// no componente vue
import { useStore } from 'vuex'
import { key } from './store'
export default {
setup () {
const store = useStore(key)
store.state.count // tipado como número
}
}
```
================================================
FILE: docs/ptbr/guide/actions.md
================================================
# Actions
<div class="scrimba"><a href="https://scrimba.com/p/pnyzgAP/c6ggR3cG" target="_blank" rel="noopener noreferrer">Tente esta lição no Scrimba</a></div>
As ações são semelhantes às mutações, as diferenças são as seguintes:
- Em vez de mudar o estado, as ações confirmam (ou fazem _commit_ de) mutações.
- As ações podem conter operações assíncronas arbitrárias.
Vamos registrar uma ação simples:
``` js
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
```
As funções manipuladoras de ação recebem um objeto _context_ que expõe o mesmo conjunto de métodos/propriedades na instância do _store_, para que você possa chamar `context.commit` para confirmar uma mutação ou acessar o estado e os _getters_ através do `conte
gitextract_cty0x9ut/
├── .babelrc
├── .eslintrc.json
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.yml
│ ├── ISSUE_TEMPLATE.md
│ ├── commit-convention.md
│ ├── contributing.md
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs/
│ ├── .vitepress/
│ │ ├── config.js
│ │ ├── styles/
│ │ │ └── styles.css
│ │ └── theme/
│ │ └── index.js
│ ├── api/
│ │ └── index.md
│ ├── guide/
│ │ ├── actions.md
│ │ ├── composition-api.md
│ │ ├── forms.md
│ │ ├── getters.md
│ │ ├── hot-reload.md
│ │ ├── index.md
│ │ ├── migrating-to-4-0-from-3-x.md
│ │ ├── modules.md
│ │ ├── mutations.md
│ │ ├── plugins.md
│ │ ├── state.md
│ │ ├── strict.md
│ │ ├── structure.md
│ │ ├── testing.md
│ │ └── typescript-support.md
│ ├── index.md
│ ├── installation.md
│ ├── ja/
│ │ ├── api/
│ │ │ └── index.md
│ │ ├── guide/
│ │ │ ├── actions.md
│ │ │ ├── composition-api.md
│ │ │ ├── forms.md
│ │ │ ├── getters.md
│ │ │ ├── hot-reload.md
│ │ │ ├── index.md
│ │ │ ├── migrating-to-4-0-from-3-x.md
│ │ │ ├── modules.md
│ │ │ ├── mutations.md
│ │ │ ├── plugins.md
│ │ │ ├── state.md
│ │ │ ├── strict.md
│ │ │ ├── structure.md
│ │ │ ├── testing.md
│ │ │ └── typescript-support.md
│ │ ├── index.md
│ │ └── installation.md
│ ├── ptbr/
│ │ ├── api/
│ │ │ └── index.md
│ │ ├── guide/
│ │ │ ├── actions.md
│ │ │ ├── composition-api.md
│ │ │ ├── forms.md
│ │ │ ├── getters.md
│ │ │ ├── hot-reload.md
│ │ │ ├── index.md
│ │ │ ├── migrating-to-4-0-from-3-x.md
│ │ │ ├── modules.md
│ │ │ ├── mutations.md
│ │ │ ├── plugins.md
│ │ │ ├── state.md
│ │ │ ├── strict.md
│ │ │ ├── structure.md
│ │ │ ├── testing.md
│ │ │ └── typescript-support.md
│ │ ├── index.md
│ │ └── installation.md
│ ├── public/
│ │ └── _redirects
│ └── zh/
│ ├── api/
│ │ └── index.md
│ ├── guide/
│ │ ├── actions.md
│ │ ├── composition-api.md
│ │ ├── forms.md
│ │ ├── getters.md
│ │ ├── hot-reload.md
│ │ ├── index.md
│ │ ├── migrating-to-4-0-from-3-x.md
│ │ ├── modules.md
│ │ ├── mutations.md
│ │ ├── plugins.md
│ │ ├── state.md
│ │ ├── strict.md
│ │ ├── structure.md
│ │ ├── testing.md
│ │ └── typescript-support.md
│ ├── index.md
│ └── installation.md
├── examples/
│ ├── classic/
│ │ ├── chat/
│ │ │ ├── api/
│ │ │ │ ├── index.js
│ │ │ │ └── mock-data.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── Message.vue
│ │ │ │ ├── MessageSection.vue
│ │ │ │ ├── Thread.vue
│ │ │ │ └── ThreadSection.vue
│ │ │ ├── css/
│ │ │ │ └── chat.css
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── counter/
│ │ │ ├── Counter.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store.js
│ │ ├── counter-hot/
│ │ │ ├── CounterControls.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── shopping-cart/
│ │ │ ├── api/
│ │ │ │ └── shop.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── ProductList.vue
│ │ │ │ └── ShoppingCart.vue
│ │ │ ├── currency.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── index.js
│ │ │ └── modules/
│ │ │ ├── cart.js
│ │ │ ├── nested.js
│ │ │ └── products.js
│ │ └── todomvc/
│ │ ├── app.js
│ │ ├── components/
│ │ │ ├── App.vue
│ │ │ └── TodoItem.vue
│ │ ├── index.html
│ │ └── store/
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── plugins.js
│ ├── composition/
│ │ ├── chat/
│ │ │ ├── api/
│ │ │ │ ├── index.js
│ │ │ │ └── mock-data.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── Message.vue
│ │ │ │ ├── MessageSection.vue
│ │ │ │ ├── Thread.vue
│ │ │ │ └── ThreadSection.vue
│ │ │ ├── css/
│ │ │ │ └── chat.css
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── counter/
│ │ │ ├── Counter.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store.js
│ │ ├── counter-hot/
│ │ │ ├── CounterControls.vue
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ └── mutations.js
│ │ ├── shopping-cart/
│ │ │ ├── api/
│ │ │ │ └── shop.js
│ │ │ ├── app.js
│ │ │ ├── components/
│ │ │ │ ├── App.vue
│ │ │ │ ├── ProductList.vue
│ │ │ │ └── ShoppingCart.vue
│ │ │ ├── currency.js
│ │ │ ├── index.html
│ │ │ └── store/
│ │ │ ├── index.js
│ │ │ └── modules/
│ │ │ ├── cart.js
│ │ │ └── products.js
│ │ └── todomvc/
│ │ ├── app.js
│ │ ├── components/
│ │ │ ├── App.vue
│ │ │ └── TodoItem.vue
│ │ ├── index.html
│ │ └── store/
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── plugins.js
│ ├── global.css
│ ├── index.html
│ ├── server.js
│ └── webpack.config.js
├── jest.config.js
├── package.json
├── rollup.config.js
├── scripts/
│ ├── build.js
│ └── release.js
├── src/
│ ├── helpers.js
│ ├── index.cjs.js
│ ├── index.js
│ ├── index.mjs
│ ├── injectKey.js
│ ├── module/
│ │ ├── module-collection.js
│ │ └── module.js
│ ├── plugins/
│ │ ├── devtool.js
│ │ └── logger.js
│ ├── store-util.js
│ ├── store.js
│ └── util.js
├── test/
│ ├── .eslintrc.json
│ ├── e2e/
│ │ ├── cart.spec.js
│ │ ├── chat.spec.js
│ │ ├── counter.spec.js
│ │ └── todomvc.spec.js
│ ├── esm/
│ │ ├── esm-import.mjs
│ │ └── esm-test.js
│ ├── helpers.js
│ ├── setup.js
│ └── unit/
│ ├── helpers.spec.js
│ ├── hot-reload.spec.js
│ ├── module/
│ │ ├── module-collection.spec.js
│ │ └── module.spec.js
│ ├── modules.spec.js
│ ├── store.spec.js
│ └── util.spec.js
└── types/
├── README.md
├── helpers.d.ts
├── index.d.ts
├── logger.d.ts
├── test/
│ ├── helpers.ts
│ ├── index.ts
│ ├── tsconfig.json
│ └── vue.ts
├── tsconfig.json
└── vue.d.ts
SYMBOL INDEX (330 symbols across 47 files)
FILE: examples/classic/chat/api/index.js
constant LATENCY (line 2) | const LATENCY = 16
function getAllMessages (line 4) | function getAllMessages (cb) {
function createMessage (line 10) | function createMessage ({ text, thread }, cb) {
FILE: examples/classic/chat/store/mutations.js
method receiveAll (line 2) | receiveAll (state, messages) {
method receiveMessage (line 20) | receiveMessage (state, message) {
method switchThread (line 24) | switchThread (state, id) {
function createThread (line 29) | function createThread (state, id, name) {
function addMessage (line 41) | function addMessage (state, message) {
function setCurrentThread (line 57) | function setCurrentThread (state, id) {
FILE: examples/classic/counter/store.js
method increment (line 15) | increment (state) {
method decrement (line 18) | decrement (state) {
method incrementIfOdd (line 28) | incrementIfOdd ({ commit, state }) {
method incrementAsync (line 33) | incrementAsync ({ commit }) {
FILE: examples/classic/shopping-cart/api/shop.js
method getProducts (line 11) | async getProducts () {
method buyProducts (line 16) | async buyProducts (products) {
function wait (line 29) | function wait (ms) {
FILE: examples/classic/shopping-cart/currency.js
function currency (line 3) | function currency (value, currency, decimals) {
FILE: examples/classic/shopping-cart/store/modules/cart.js
method checkout (line 34) | async checkout ({ commit, state }, products) {
method addProductToCart (line 50) | addProductToCart ({ state, commit }, product) {
method pushProductToCart (line 67) | pushProductToCart (state, { id }) {
method incrementItemQuantity (line 74) | incrementItemQuantity (state, { id }) {
method setCartItems (line 79) | setCartItems (state, { items }) {
method setCheckoutStatus (line 83) | setCheckoutStatus (state, status) {
FILE: examples/classic/shopping-cart/store/modules/products.js
method getAllProducts (line 13) | async getAllProducts ({ commit }) {
method setProducts (line 21) | setProducts (state, products) {
method decrementProductInventory (line 25) | decrementProductInventory (state, { id }) {
FILE: examples/classic/todomvc/store/actions.js
method addTodo (line 2) | addTodo ({ commit }, text) {
method removeTodo (line 9) | removeTodo ({ commit }, todo) {
method toggleTodo (line 13) | toggleTodo ({ commit }, todo) {
method editTodo (line 17) | editTodo ({ commit }, { todo, value }) {
method toggleAll (line 21) | toggleAll ({ state, commit }, done) {
method clearCompleted (line 27) | clearCompleted ({ state, commit }) {
FILE: examples/classic/todomvc/store/mutations.js
constant STORAGE_KEY (line 1) | const STORAGE_KEY = 'todos-vuejs'
method addTodo (line 9) | addTodo (state, todo) {
method removeTodo (line 13) | removeTodo (state, todo) {
method editTodo (line 17) | editTodo (state, { todo, text = todo.text, done = todo.done }) {
FILE: examples/composition/chat/api/index.js
constant LATENCY (line 2) | const LATENCY = 16
function getAllMessages (line 4) | function getAllMessages (cb) {
function createMessage (line 10) | function createMessage ({ text, thread }, cb) {
FILE: examples/composition/chat/store/mutations.js
method receiveAll (line 2) | receiveAll (state, messages) {
method receiveMessage (line 20) | receiveMessage (state, message) {
method switchThread (line 24) | switchThread (state, id) {
function createThread (line 29) | function createThread (state, id, name) {
function addMessage (line 41) | function addMessage (state, message) {
function setCurrentThread (line 57) | function setCurrentThread (state, id) {
FILE: examples/composition/counter/store.js
method increment (line 15) | increment (state) {
method decrement (line 18) | decrement (state) {
method incrementIfOdd (line 28) | incrementIfOdd ({ commit, state }) {
method incrementAsync (line 33) | incrementAsync ({ commit }) {
FILE: examples/composition/shopping-cart/api/shop.js
method getProducts (line 11) | getProducts (cb) {
method buyProducts (line 15) | buyProducts (products, cb, errorCb) {
FILE: examples/composition/shopping-cart/currency.js
function currency (line 3) | function currency (value, currency, decimals) {
FILE: examples/composition/shopping-cart/store/modules/cart.js
method checkout (line 33) | checkout ({ commit, state }, products) {
method addProductToCart (line 49) | addProductToCart ({ state, commit }, product) {
method pushProductToCart (line 66) | pushProductToCart (state, { id }) {
method incrementItemQuantity (line 73) | incrementItemQuantity (state, { id }) {
method setCartItems (line 78) | setCartItems (state, { items }) {
method setCheckoutStatus (line 82) | setCheckoutStatus (state, status) {
FILE: examples/composition/shopping-cart/store/modules/products.js
method getAllProducts (line 13) | getAllProducts ({ commit }) {
method setProducts (line 22) | setProducts (state, products) {
method decrementProductInventory (line 26) | decrementProductInventory (state, { id }) {
FILE: examples/composition/todomvc/store/actions.js
method addTodo (line 2) | addTodo ({ commit }, text) {
method removeTodo (line 9) | removeTodo ({ commit }, todo) {
method toggleTodo (line 13) | toggleTodo ({ commit }, todo) {
method editTodo (line 17) | editTodo ({ commit }, { todo, value }) {
method toggleAll (line 21) | toggleAll ({ state, commit }, done) {
method clearCompleted (line 27) | clearCompleted ({ state, commit }) {
FILE: examples/composition/todomvc/store/mutations.js
constant STORAGE_KEY (line 1) | const STORAGE_KEY = 'todos-vuejs'
method addTodo (line 9) | addTodo (state, todo) {
method removeTodo (line 13) | removeTodo (state, todo) {
method editTodo (line 17) | editTodo (state, { todo, text = todo.text, done = todo.done }) {
FILE: examples/webpack.config.js
function buildEntry (line 6) | function buildEntry (dirname) {
FILE: rollup.config.js
function createEntries (line 56) | function createEntries() {
function createEntry (line 60) | function createEntry(config) {
FILE: scripts/build.js
function run (line 16) | async function run() {
function build (line 21) | async function build() {
function copy (line 25) | async function copy() {
function checkAllSizes (line 29) | function checkAllSizes() {
function checkSize (line 35) | function checkSize(file) {
FILE: scripts/release.js
function main (line 25) | async function main() {
function updatePackage (line 112) | function updatePackage(version) {
FILE: src/helpers.js
function normalizeMap (line 145) | function normalizeMap (map) {
function isValidMap (line 159) | function isValidMap (map) {
function normalizeNamespace (line 168) | function normalizeNamespace (fn) {
function getModuleByNamespace (line 187) | function getModuleByNamespace (store, helper, namespace) {
FILE: src/injectKey.js
function useStore (line 5) | function useStore (key = null) {
FILE: src/module/module-collection.js
class ModuleCollection (line 4) | class ModuleCollection {
method constructor (line 5) | constructor (rawRootModule) {
method get (line 10) | get (path) {
method getNamespace (line 16) | getNamespace (path) {
method update (line 24) | update (rawRootModule) {
method register (line 28) | register (path, rawModule, runtime = true) {
method unregister (line 49) | unregister (path) {
method isRegistered (line 71) | isRegistered (path) {
function update (line 83) | function update (path, targetModule, newModule) {
function assertRawModule (line 129) | function assertRawModule (path, rawModule) {
function makeAssertionMessage (line 144) | function makeAssertionMessage (path, key, type, value, expected) {
FILE: src/module/module.js
class Module (line 4) | class Module {
method constructor (line 5) | constructor (rawModule, runtime) {
method namespaced (line 17) | get namespaced () {
method addChild (line 21) | addChild (key, module) {
method removeChild (line 25) | removeChild (key) {
method getChild (line 29) | getChild (key) {
method hasChild (line 33) | hasChild (key) {
method update (line 37) | update (rawModule) {
method forEachChild (line 50) | forEachChild (fn) {
method forEachGetter (line 54) | forEachGetter (fn) {
method forEachAction (line 60) | forEachAction (fn) {
method forEachMutation (line 66) | forEachMutation (fn) {
FILE: src/plugins/devtool.js
constant LABEL_VUEX_BINDINGS (line 4) | const LABEL_VUEX_BINDINGS = 'vuex bindings'
constant MUTATIONS_LAYER_ID (line 5) | const MUTATIONS_LAYER_ID = 'vuex:mutations'
constant ACTIONS_LAYER_ID (line 6) | const ACTIONS_LAYER_ID = 'vuex:actions'
constant INSPECTOR_ID (line 7) | const INSPECTOR_ID = 'vuex'
function addDevtools (line 11) | function addDevtools (app, store) {
constant COLOR_LIME_500 (line 158) | const COLOR_LIME_500 = 0x84cc16
constant COLOR_DARK (line 159) | const COLOR_DARK = 0x666666
constant COLOR_WHITE (line 160) | const COLOR_WHITE = 0xffffff
constant TAG_NAMESPACED (line 162) | const TAG_NAMESPACED = {
function extractNameFromPath (line 171) | function extractNameFromPath (path) {
function formatStoreForInspectorTree (line 179) | function formatStoreForInspectorTree (module, path) {
function flattenStoreForInspectorTree (line 202) | function flattenStoreForInspectorTree (result, module, filter, path) {
function formatStoreForInspectorState (line 219) | function formatStoreForInspectorState (module, getters, path) {
function transformPathsToObjectTree (line 242) | function transformPathsToObjectTree (getters) {
function getStoreModule (line 270) | function getStoreModule (moduleMap, path) {
function canThrow (line 284) | function canThrow (cb) {
FILE: src/plugins/logger.js
function createLogger (line 5) | function createLogger ({
function startMessage (line 59) | function startMessage (logger, message, collapsed) {
function endMessage (line 72) | function endMessage (logger) {
function getFormattedTime (line 80) | function getFormattedTime () {
function repeat (line 85) | function repeat (str, times) {
function pad (line 89) | function pad (num, maxLength) {
FILE: src/store-util.js
function genericSubscribe (line 4) | function genericSubscribe (fn, subs, options) {
function resetStore (line 18) | function resetStore (store, hot) {
function resetStoreState (line 30) | function resetStoreState (store, state, hot) {
function installModule (line 89) | function installModule (store, rootState, path, module, hot) {
function makeLocalContext (line 144) | function makeLocalContext (store, namespace, path) {
function makeLocalGetters (line 197) | function makeLocalGetters (store, namespace) {
function registerMutation (line 222) | function registerMutation (store, type, handler, local) {
function registerAction (line 229) | function registerAction (store, type, handler, local) {
function registerGetter (line 254) | function registerGetter (store, type, rawGetter, local) {
function enableStrictMode (line 271) | function enableStrictMode (store) {
function getNestedState (line 279) | function getNestedState (state, path) {
function unifyObjectStyle (line 283) | function unifyObjectStyle (type, payload, options) {
FILE: src/store.js
function createStore (line 15) | function createStore (options) {
class Store (line 19) | class Store {
method constructor (line 20) | constructor (options = {}) {
method install (line 78) | install (app, injectKey) {
method state (line 91) | get state () {
method state (line 95) | set state (v) {
method commit (line 101) | commit (_type, _payload, _options) {
method dispatch (line 138) | dispatch (_type, _payload) {
method subscribe (line 199) | subscribe (fn, options) {
method subscribeAction (line 203) | subscribeAction (fn, options) {
method watch (line 208) | watch (getter, cb, options) {
method replaceState (line 215) | replaceState (state) {
method registerModule (line 221) | registerModule (path, rawModule, options = {}) {
method unregisterModule (line 235) | unregisterModule (path) {
method hasModule (line 250) | hasModule (path) {
method hotUpdate (line 260) | hotUpdate (newOptions) {
method _withCommit (line 265) | _withCommit (fn) {
FILE: src/util.js
function find (line 9) | function find (list, f) {
function deepCopy (line 22) | function deepCopy (obj, cache = []) {
function forEachValue (line 52) | function forEachValue (obj, fn) {
function isObject (line 56) | function isObject (obj) {
function isPromise (line 60) | function isPromise (val) {
function assert (line 64) | function assert (condition, msg) {
function partial (line 68) | function partial (fn, arg) {
FILE: test/e2e/cart.spec.js
function testCart (line 6) | async function testCart (url) {
FILE: test/e2e/chat.spec.js
function testChat (line 6) | async function testChat (url) {
FILE: test/e2e/counter.spec.js
function testCounter (line 6) | async function testCounter (url) {
FILE: test/e2e/todomvc.spec.js
function testTodoMVC (line 21) | async function testTodoMVC (url) {
FILE: test/helpers.js
function mount (line 4) | function mount (store, component) {
function createElement (line 16) | function createElement () {
constant E2E_TIMEOUT (line 24) | const E2E_TIMEOUT = 30 * 1000
function setupPuppeteer (line 30) | function setupPuppeteer () {
FILE: test/unit/helpers.spec.js
method inc (line 151) | inc (state, amount) {
method plus (line 158) | plus (commit, amount) {
method inc (line 199) | inc (state, amount) {
method plus (line 208) | plus (commit, amount) {
method foo (line 454) | foo (dispatch, arg) {
method foo (line 502) | foo (dispatch, arg) {
FILE: test/unit/hot-reload.spec.js
constant TEST (line 5) | const TEST = 'TEST'
method [TEST] (line 11) | [TEST] (state, n) {
method [TEST] (line 60) | [TEST] (state, n) {
method [TEST] (line 115) | [TEST] (state, n) {
method [TEST] (line 123) | [TEST] (state, n) {
method [TEST] (line 131) | [TEST] (state, n) {
method [TEST] (line 141) | [TEST] (state, n) {
method [TEST] (line 149) | [TEST] (state, n) {
method [TEST] (line 161) | [TEST] (state, n) {
method [TEST] (line 183) | [TEST] (state, n) {
method [TEST] (line 188) | [TEST] ({ commit }) {
method [TEST] (line 195) | [TEST] ({ commit }) {
method [TEST] (line 208) | [TEST] ({ commit }) {
method [TEST] (line 219) | [TEST] ({ commit }) {
method [TEST] (line 226) | [TEST] ({ commit }) {
method check (line 249) | check ({ getters }, value) {
FILE: test/unit/modules.spec.js
constant TEST (line 5) | const TEST = 'TEST'
method getState (line 138) | getState (state) {
method created (line 150) | created () {
method render (line 162) | render () {
method state (line 205) | state () {
method [TEST] (line 209) | [TEST] (state, n) {
method state (line 232) | state () {
method [TEST] (line 236) | [TEST] (state, n) {
method [TEST] (line 268) | [TEST] (state, n) {
method [TEST] (line 319) | [TEST] ({ state, rootState }) {
method test (line 555) | test ({ dispatch, commit, getters, rootGetters }) {
method test (line 601) | test ({ dispatch, commit, getters }) {
method state (line 628) | state () {
method [TEST] (line 650) | [TEST] () {
method [TEST] (line 657) | [TEST] () {
method handler (line 679) | handler () {
method handler (line 690) | handler () {
method handler (line 700) | handler () {
method [TEST] (line 710) | [TEST] () {
method [TEST] (line 736) | [TEST] (state, n) {
FILE: test/unit/store.spec.js
constant TEST (line 5) | const TEST = 'TEST'
method [TEST] (line 15) | [TEST] (state, n) {
method [TEST] (line 30) | [TEST] (state, payload) {
method undefined (line 50) | undefined (state, n) {
method [TEST] (line 67) | [TEST] (state, n) {
method [TEST] (line 72) | [TEST] ({ commit }, n) {
method [TEST] (line 87) | [TEST] (state, n) {
method [TEST] (line 92) | [TEST] ({ commit }, payload) {
method [TEST] (line 110) | [TEST] (state, n) {
method [TEST] (line 115) | [TEST] ({ commit }, n) {
method [TEST] (line 138) | [TEST] (state, n) {
method [TEST] (line 143) | [TEST] ({ commit }, n) {
method [TEST] (line 168) | [TEST] () {
method [TEST] (line 196) | [TEST] (state, n) {
method undefined (line 203) | undefined ({ commit }, n) {
method [TEST] (line 223) | [TEST] (state, n) {
method check (line 228) | check ({ getters }, value) {
method [TEST] (line 254) | [TEST] () {}
method [TEST] (line 277) | [TEST] (state, n) {
FILE: test/unit/util.spec.js
function plus (line 55) | function plus (value, key) {
FILE: types/helpers.d.ts
type Computed (line 4) | type Computed = () => any;
type InlineComputed (line 5) | type InlineComputed<T extends Function> = T extends (...args: any[]) => ...
type MutationMethod (line 6) | type MutationMethod = (...args: any[]) => void;
type ActionMethod (line 7) | type ActionMethod = (...args: any[]) => Promise<any>;
type InlineMethod (line 8) | type InlineMethod<T extends (fn: any, ...args: any[]) => any> = T extend...
type CustomVue (line 9) | type CustomVue = ComponentPublicInstance & Record<string, any>;
type Mapper (line 11) | interface Mapper<R> {
type MapperWithNamespace (line 16) | interface MapperWithNamespace<R> {
type MapperForState (line 21) | interface MapperForState {
type MapperForStateWithNamespace (line 27) | interface MapperForStateWithNamespace {
type MapperForAction (line 34) | interface MapperForAction {
type MapperForActionWithNamespace (line 40) | interface MapperForActionWithNamespace {
type MapperForMutation (line 47) | interface MapperForMutation {
type MapperForMutationWithNamespace (line 53) | interface MapperForMutationWithNamespace {
type NamespacedMappers (line 61) | interface NamespacedMappers {
FILE: types/index.d.ts
class Store (line 12) | class Store<S> {
type Dispatch (line 52) | interface Dispatch {
type Commit (line 57) | interface Commit {
type ActionContext (line 62) | interface ActionContext<S, R> {
type Payload (line 71) | interface Payload {
type MutationPayload (line 75) | interface MutationPayload extends Payload {
type ActionPayload (line 79) | interface ActionPayload extends Payload {
type SubscribeOptions (line 83) | interface SubscribeOptions {
type ActionSubscriber (line 87) | type ActionSubscriber<P, S> = (action: P, state: S) => any;
type ActionErrorSubscriber (line 88) | type ActionErrorSubscriber<P, S> = (action: P, state: S, error: Error) =...
type ActionSubscribersObject (line 90) | interface ActionSubscribersObject<P, S> {
type SubscribeActionOptions (line 96) | type SubscribeActionOptions<P, S> = ActionSubscriber<P, S> | ActionSubsc...
type DispatchOptions (line 98) | interface DispatchOptions {
type CommitOptions (line 102) | interface CommitOptions {
type StoreOptions (line 107) | interface StoreOptions<S> {
type ActionHandler (line 118) | type ActionHandler<S, R> = (this: Store<R>, injectee: ActionContext<S, R...
type ActionObject (line 119) | interface ActionObject<S, R> {
type Getter (line 124) | type Getter<S, R> = (state: S, getters: any, rootState: R, rootGetters: ...
type Action (line 125) | type Action<S, R> = ActionHandler<S, R> | ActionObject<S, R>;
type Mutation (line 126) | type Mutation<S> = (state: S, payload?: any) => any;
type Plugin (line 127) | type Plugin<S> = (store: Store<S>) => any;
type Module (line 129) | interface Module<S, R> {
type ModuleOptions (line 138) | interface ModuleOptions {
type GetterTree (line 142) | interface GetterTree<S, R> {
type ActionTree (line 146) | interface ActionTree<S, R> {
type MutationTree (line 150) | interface MutationTree<S> {
type ModuleTree (line 154) | interface ModuleTree<R> {
FILE: types/logger.d.ts
type Logger (line 3) | interface Logger extends Partial<Pick<Console, 'groupCollapsed' | 'group...
type LoggerOption (line 8) | interface LoggerOption<S> {
FILE: types/test/helpers.ts
method useThis (line 45) | useThis(state: any, getters: any): any {
method otherComputed (line 56) | otherComputed () {
method r (line 67) | r (dispatch, a: string, b: number, c: boolean) {
method u (line 82) | u (dispatch, a: string, b: number, c: boolean) {
method x (line 98) | x (commit, a: string, b: number, c: boolean) {
method aa (line 113) | aa (commit, a: string, b: number, c: boolean) {
method ad (line 129) | ad (dispatch, value: string) {
method ag (line 139) | ag (commit, value: string) {
method otherMethod (line 144) | otherMethod () {}
method created (line 147) | created() {
FILE: types/test/index.ts
method before (line 48) | before(action, state) {
method before (line 56) | before(action, state) {
method after (line 61) | after(action, state) {
method before (line 69) | before(action, state) {
method error (line 74) | error(action, state, error) {
method before (line 83) | before(action, state) {
method after (line 88) | after(action, state) {
method error (line 93) | error(action, state, error) {
method after (line 102) | after(action, state) {
method after (line 110) | after(action, state) {
method error (line 115) | error(action, state, error) {
method error (line 124) | error(action, state, error) {
type State (line 138) | interface State {
method foo (line 167) | foo ({ state, getters, dispatch, commit }, payload) {
method bar (line 176) | bar (state, payload) {}
method foo (line 193) | foo ({ state, getters, dispatch, commit }, payload) {
method bar (line 202) | bar (state, payload) {}
type RootState (line 218) | interface RootState {
type ActionStore (line 235) | type ActionStore = Vuex.ActionContext<{ value: number }, RootState>
method foo (line 242) | foo (
method bar (line 254) | bar (state: { value: number }, payload: { amount: number }) {
method foo (line 275) | foo(context: ActionStore, payload) {
method foo (line 293) | foo () {}
method foo (line 296) | foo () {}
method handler (line 305) | handler ({ dispatch }) {
method handler (line 310) | handler ({ dispatch }) {
method count (line 324) | count (state, getters, rootState, rootGetters) {
method test (line 330) | test ({ dispatch, commit, getters, rootGetters }) {
method foo (line 340) | foo () {}
method foo (line 343) | foo () {}
type RootState (line 353) | interface RootState {
type RootState (line 390) | interface RootState {
type ActionStore (line 399) | type ActionStore = Vuex.ActionContext<{ value: number }, RootState>
method foo (line 406) | foo (store: ActionStore, payload: number) {}
method bar (line 410) | bar (state: { value: number }, payload: number) {}
function plugin (line 451) | function plugin (store: Vuex.Store<{ value: number }>) {
class MyLogger (line 458) | class MyLogger {
method log (line 459) | log(message: string) {
FILE: types/vue.d.ts
type ComponentCustomOptions (line 9) | interface ComponentCustomOptions {
Condensed preview — 222 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (559K chars).
[
{
"path": ".babelrc",
"chars": 117,
"preview": "{\n \"presets\": [\n [\"@babel/preset-env\", {\n \"exclude\": [\n \"transform-regenerator\"\n ]\n }]\n ]\n}\n"
},
{
"path": ".eslintrc.json",
"chars": 148,
"preview": "{\n \"root\": true,\n \"extends\": [\n \"plugin:vue-libs/recommended\"\n ],\n \"globals\": {\n \"__DEV__\": true,\n \"__VUE_P"
},
{
"path": ".github/FUNDING.yml",
"chars": 75,
"preview": "github: [yyx990803, kiaking, ktsn]\nopen_collective: vuejs\npatreon: evanyou\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 2084,
"preview": "name: \"\\U0001F41E Bug report\"\ndescription: Create a report to help us improve\nlabels: ['bug: pending triage']\nbody:\n - "
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 204,
"preview": "<!--\nIMPORTANT: Please use the following link to create a new issue:\n\n https://new-issue.vuejs.org/?repo=vuejs/vuex\n\nIf"
},
{
"path": ".github/commit-convention.md",
"chars": 2931,
"preview": "## Git Commit Message Convention\n\n> This is adapted from [Angular's commit convention](https://github.com/conventional-c"
},
{
"path": ".github/contributing.md",
"chars": 1692,
"preview": "# Vuex Contributing Guide\n\nHi! We're really excited that you are interested in contributing to Vuex. Before submitting y"
},
{
"path": ".github/workflows/ci.yml",
"chars": 474,
"preview": "name: 'ci'\non:\n push:\n branches:\n - '**'\n pull_request:\n branches:\n - main\n\npermissions:\n contents: r"
},
{
"path": ".gitignore",
"chars": 107,
"preview": "/dist\n/coverage\n/docs/.vitepress/dist\n/test/e2e/reports\n/test/e2e/screenshots\n*.log\n.DS_Store\nnode_modules\n"
},
{
"path": "CHANGELOG.md",
"chars": 25511,
"preview": "# [4.1.0](https://github.com/vuejs/vuex/compare/v4.0.2...v4.1.0) (2022-10-14)\n\n### Vue Core Version Requirement Change\n\n"
},
{
"path": "LICENSE",
"chars": 1083,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015-present Evan You\n\nPermission is hereby granted, free of charge, to any person "
},
{
"path": "README.md",
"chars": 2765,
"preview": "# Vuex\n\n[](https://npmjs.com/package/vuex)\n[: Store<S>"
},
{
"path": "docs/guide/actions.md",
"chars": 5062,
"preview": "# Actions\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/guide/composition-api.md",
"chars": 1507,
"preview": "# Composition API\n\nTo access the store within the `setup` hook, you can call the `useStore` function. This is the equiva"
},
{
"path": "docs/guide/forms.md",
"chars": 1614,
"preview": "# Form Handling\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener nor"
},
{
"path": "docs/guide/getters.md",
"chars": 2960,
"preview": "# Getters\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/guide/hot-reload.md",
"chars": 2126,
"preview": "# Hot Reloading\n\nVuex supports hot-reloading mutations, modules, actions and getters during development, using webpack's"
},
{
"path": "docs/guide/index.md",
"chars": 2697,
"preview": "# Getting Started\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener no"
},
{
"path": "docs/guide/migrating-to-4-0-from-3-x.md",
"chars": 3749,
"preview": "# Migrating to 4.0 from 3.x\n\nAlmost all Vuex 4 APIs have remained unchanged from Vuex 3. However, there are still a few "
},
{
"path": "docs/guide/modules.md",
"chars": 11278,
"preview": "# Modules\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/guide/mutations.md",
"chars": 4882,
"preview": "# Mutations\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener norefer"
},
{
"path": "docs/guide/plugins.md",
"chars": 4179,
"preview": "# Plugins\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/guide/state.md",
"chars": 4310,
"preview": "# State\n\n## Single State Tree\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel="
},
{
"path": "docs/guide/strict.md",
"chars": 857,
"preview": "# Strict Mode\n\nTo enable strict mode, simply pass in `strict: true` when creating a Vuex store:\n\n```js\nconst store = cre"
},
{
"path": "docs/guide/structure.md",
"chars": 1221,
"preview": "# Application Structure\n\nVuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-lev"
},
{
"path": "docs/guide/testing.md",
"chars": 6214,
"preview": "# Testing\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/guide/typescript-support.md",
"chars": 3660,
"preview": "# TypeScript Support\n\nVuex provides its typings so you can use TypeScript to write a store definition. You don't need an"
},
{
"path": "docs/index.md",
"chars": 4326,
"preview": "# What is Vuex?\n\n::: tip Pinia is now the new default\n\nThe official state management library for Vue has changed to [Pin"
},
{
"path": "docs/installation.md",
"chars": 859,
"preview": "# Installation\n\n## Direct Download / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg."
},
{
"path": "docs/ja/api/index.md",
"chars": 9445,
"preview": "---\nsidebar: auto\n---\n\n# API リファレンス\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n"
},
{
"path": "docs/ja/guide/actions.md",
"chars": 4135,
"preview": "# アクション\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer\""
},
{
"path": "docs/ja/guide/composition-api.md",
"chars": 1245,
"preview": "# Composition API\n\n`setup` フックの中でストアにアクセスするには、`useStore` 関数を呼び出します。これは、Option API を使って、コンポーネント内で `this.$store` を取得するのと同等"
},
{
"path": "docs/ja/guide/forms.md",
"chars": 1243,
"preview": "# フォームの扱い\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/ja/guide/getters.md",
"chars": 2314,
"preview": "# ゲッター\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\">S"
},
{
"path": "docs/ja/guide/hot-reload.md",
"chars": 1967,
"preview": "# ホットリローディング\n\nVuex は webpack の [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/) を使用する"
},
{
"path": "docs/ja/guide/index.md",
"chars": 1852,
"preview": "# Vuex 入門\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/ja/guide/migrating-to-4-0-from-3-x.md",
"chars": 2746,
"preview": "# 3.x から 4.0 への移行\n\nほとんどすべての Vuex 4 の API は、Vuex 3 から変更されていません。しかし、修正が必要な破壊的変更がいくつかあります。\n\n- [破壊的変更](#破壊的変更)\n - [インストール手順"
},
{
"path": "docs/ja/guide/modules.md",
"chars": 8901,
"preview": "# モジュール\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer\""
},
{
"path": "docs/ja/guide/mutations.md",
"chars": 3647,
"preview": "# ミューテーション\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferr"
},
{
"path": "docs/ja/guide/plugins.md",
"chars": 3429,
"preview": "# プラグイン \n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/ja/guide/state.md",
"chars": 3000,
"preview": "# ステート\n\n## 単一ステートツリー\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener"
},
{
"path": "docs/ja/guide/strict.md",
"chars": 510,
"preview": "# 厳格モード\n\n厳格(strict)モードを有効にするには Vuex store を作成するときに、ただ `strict: true` を指定するだけです:\n\n```js\nconst store = createStore({\n // "
},
{
"path": "docs/ja/guide/structure.md",
"chars": 883,
"preview": "# アプリケーションの構造\n\nVuex は実際のところ、あなたがコードを構造化する方法を制限しません。もっと正確に言うと、それより高いレベルの原理原則を適用させます:\n\n1. アプリケーションレベルの状態はストアに集約されます。\n\n2. 状"
},
{
"path": "docs/ja/guide/testing.md",
"chars": 5291,
"preview": "# テスト\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">S"
},
{
"path": "docs/ja/guide/typescript-support.md",
"chars": 2910,
"preview": "# TypeScript サポート\n\nVuex は型付けを提供しているので、TypeScript を使ってストア定義を書くことができます。Vuex には特別な TypeScript の設定は必要ありません。[Vue の基本的な TypeSc"
},
{
"path": "docs/ja/index.md",
"chars": 2319,
"preview": "# Vuex とは何か?\n\n::: tip 注意\nこれは、Vue 3 で動作する Vuex 4 のためのドキュメントです。Vue 2 で動作する Vuex 3 のドキュメントをお探しの方は、[こちらをご覧ください](https://vuex"
},
{
"path": "docs/ja/installation.md",
"chars": 716,
"preview": "# インストール\n\n## 直接ダウンロードする / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https:"
},
{
"path": "docs/ptbr/api/index.md",
"chars": 13917,
"preview": "---\nsidebar: auto\n---\n\n# Referência da API\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Stor"
},
{
"path": "docs/ptbr/guide/actions.md",
"chars": 5415,
"preview": "# Actions\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/ptbr/guide/composition-api.md",
"chars": 1647,
"preview": "# API de Composição (ou Composition API)\n\nPara acessar o _store_ dentro do gatilho (ou _hook_) `setup`, você pode chamar"
},
{
"path": "docs/ptbr/guide/forms.md",
"chars": 1684,
"preview": "# Manipulação de Formulários\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel="
},
{
"path": "docs/ptbr/guide/getters.md",
"chars": 3068,
"preview": "# Getters\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/ptbr/guide/hot-reload.md",
"chars": 2224,
"preview": "# Hot Reloading (Recarregamento Rápido)\n\nO Vuex suporta _hot-reloading_ de mutações, módulos, ações e _getters_ durante "
},
{
"path": "docs/ptbr/guide/index.md",
"chars": 2948,
"preview": "# Começando\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferr"
},
{
"path": "docs/ptbr/guide/migrating-to-4-0-from-3-x.md",
"chars": 4159,
"preview": "# Migrando para versão 4.0 da versão 3.x\n\nQuase todas as APIs do Vuex 4 permaneceram inalteradas desde o Vuex 3. No enta"
},
{
"path": "docs/ptbr/guide/modules.md",
"chars": 11361,
"preview": "# Módulos\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/ptbr/guide/mutations.md",
"chars": 5371,
"preview": "# Mutações\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferr"
},
{
"path": "docs/ptbr/guide/plugins.md",
"chars": 4583,
"preview": "# Plugins\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferre"
},
{
"path": "docs/ptbr/guide/state.md",
"chars": 4653,
"preview": "# Estado\n\n## Árvore Única de Estado\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank"
},
{
"path": "docs/ptbr/guide/strict.md",
"chars": 962,
"preview": "# Strict Mode\n\nPara habilitar o modo estrito, simplesmente passe `strict: true` ao criar um _store_ Vuex:\n\n```js\nconst s"
},
{
"path": "docs/ptbr/guide/structure.md",
"chars": 1302,
"preview": "# Estrutura da Aplicação\n\nO Vuex não restringe realmente como você estrutura seu código. Em vez disso, ele impõe um conj"
},
{
"path": "docs/ptbr/guide/testing.md",
"chars": 6661,
"preview": "# Testando\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferr"
},
{
"path": "docs/ptbr/guide/typescript-support.md",
"chars": 4091,
"preview": "# Suporte ao TypeScript\n\nO Vuex fornece suas tipagens para que você possa usar o TypeScript para escrever uma definição "
},
{
"path": "docs/ptbr/index.md",
"chars": 4329,
"preview": "# O que é Vuex?\n\n::: tip NOTE\nEsta documentação é para o Vuex 4, que funciona com Vue 3. Se você está procurando a docum"
},
{
"path": "docs/ptbr/installation.md",
"chars": 899,
"preview": "# Instalação\n\n## Download Direto / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.co"
},
{
"path": "docs/public/_redirects",
"chars": 471,
"preview": "# redirect old urls to root\n\n/en/api.html /api/\n/en/intro.html /en/guide/\n/en/* /guide/:splat\n\n/ptbr/api.html /api/\n/p"
},
{
"path": "docs/zh/api/index.md",
"chars": 8794,
"preview": "---\nsidebar: auto\n---\n\n# API 参考\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n 创建"
},
{
"path": "docs/zh/guide/actions.md",
"chars": 3593,
"preview": "# Action\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/zh/guide/composition-api.md",
"chars": 1115,
"preview": "# 组合式API\n\n可以通过调用 `useStore` 函数,来在 `setup` 钩子函数中访问 store。这与在组件中使用选项式 API 访问 `this.$store` 是等效的。\n\n```js\nimport { useStore "
},
{
"path": "docs/zh/guide/forms.md",
"chars": 1172,
"preview": "# 表单处理\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferrer\">"
},
{
"path": "docs/zh/guide/getters.md",
"chars": 2118,
"preview": "# Getter\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\""
},
{
"path": "docs/zh/guide/hot-reload.md",
"chars": 1785,
"preview": "# 热重载\n\n使用 webpack 的 [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/),Vuex 支持在开发过程中热重载"
},
{
"path": "docs/zh/guide/index.md",
"chars": 1627,
"preview": "# 开始\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer\">在 S"
},
{
"path": "docs/zh/guide/migrating-to-4-0-from-3-x.md",
"chars": 2500,
"preview": "# 从 3.x 迁移到 4.0\n\n几乎所有的 Vuex 4 API 都与 Vuex 3 保持不变。但是,仍有一些非兼容性变更需要注意。\n\n- [非兼容性变更](#非兼容性变更)\n - [安装过程](#安装过程)\n - [TypeScri"
},
{
"path": "docs/zh/guide/modules.md",
"chars": 8091,
"preview": "# Module\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer"
},
{
"path": "docs/zh/guide/mutations.md",
"chars": 3136,
"preview": "# Mutation\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferr"
},
{
"path": "docs/zh/guide/plugins.md",
"chars": 3023,
"preview": "# 插件\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer\">在 "
},
{
"path": "docs/zh/guide/state.md",
"chars": 2451,
"preview": "# State\n\n## 单一状态树\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener no"
},
{
"path": "docs/zh/guide/strict.md",
"chars": 394,
"preview": "# 严格模式\n\n开启严格模式,仅需在创建 store 的时候传入 `strict: true`:\n\n``` js\nconst store = createStore({\n // ...\n strict: true\n})\n```\n\n在严格"
},
{
"path": "docs/zh/guide/structure.md",
"chars": 686,
"preview": "# 项目结构\n\nVuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:\n\n1. 应用层级的状态应该集中到单个 store 对象中。\n\n2. 提交 **mutation** 是更改状态的唯一方法,并且这个过程是同步的。\n\n3. 异"
},
{
"path": "docs/zh/guide/testing.md",
"chars": 5023,
"preview": "# 测试\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">在 "
},
{
"path": "docs/zh/guide/typescript-support.md",
"chars": 2721,
"preview": "# TypeScript 支持\n\nVuex 提供了类型声明,因此可以使用 TypeScript 定义 store,并且不需要任何特殊的 TypeScript 配置。请遵循 [Vue 的基本 TypeScript 配置](https://v3"
},
{
"path": "docs/zh/index.md",
"chars": 1783,
"preview": "# Vuex 是什么?\n\n::: tip 提示\n这是与 Vue 3 匹配的 Vuex 4 的文档。如果您在找与 Vue 2 匹配的 Vuex 3 的文档,[请在这里查看](https://v3.vuex.vuejs.org/zh/)。\n::"
},
{
"path": "docs/zh/installation.md",
"chars": 651,
"preview": "# 安装\n\n## 直接下载 / CDN 引用\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg"
},
{
"path": "examples/classic/chat/api/index.js",
"chars": 454,
"preview": "const data = require('./mock-data')\nconst LATENCY = 16\n\nexport function getAllMessages (cb) {\n setTimeout(() => {\n c"
},
{
"path": "examples/classic/chat/api/mock-data.js",
"chars": 1397,
"preview": "module.exports = [\n {\n id: 'm_1',\n threadID: 't_1',\n threadName: 'Jing and Bill',\n authorName: 'Bill',\n "
},
{
"path": "examples/classic/chat/app.js",
"chars": 234,
"preview": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { getAllMessag"
},
{
"path": "examples/classic/chat/components/App.vue",
"chars": 384,
"preview": "<style src=\"../css/chat.css\"></style>\n\n<template>\n <div class=\"chatapp\">\n <thread-section></thread-section>\n <mes"
},
{
"path": "examples/classic/chat/components/Message.vue",
"chars": 449,
"preview": "<template>\n <li class=\"message-list-item\">\n <h5 class=\"message-author-name\">{{ message.authorName }}</h5>\n <div c"
},
{
"path": "examples/classic/chat/components/MessageSection.vue",
"chars": 1135,
"preview": "<template>\n <div class=\"message-section\">\n <h3 class=\"message-thread-heading\">{{ thread.name }}</h3>\n <ul class=\""
},
{
"path": "examples/classic/chat/components/Thread.vue",
"chars": 567,
"preview": "<template>\n <li\n class=\"thread-list-item\"\n :class=\"{ active }\"\n @click=\"$emit('switch-thread', thread.id)\">\n "
},
{
"path": "examples/classic/chat/components/ThreadSection.vue",
"chars": 716,
"preview": "<template>\n <div class=\"thread-section\">\n <div class=\"thread-count\">\n <span v-show=\"unreadCount\">\n Unrea"
},
{
"path": "examples/classic/chat/css/chat.css",
"chars": 1977,
"preview": "/**\n * This file is provided by Facebook for testing and evaluation purposes\n * only. Facebook reserves all rights not e"
},
{
"path": "examples/classic/chat/index.html",
"chars": 367,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex chat example</title>\n <link href"
},
{
"path": "examples/classic/chat/store/actions.js",
"chars": 390,
"preview": "import * as api from '../api'\n\nexport const getAllMessages = ({ commit }) => {\n api.getAllMessages(messages => {\n co"
},
{
"path": "examples/classic/chat/store/getters.js",
"chars": 680,
"preview": "export const threads = state => state.threads\n\nexport const currentThread = state => {\n return state.currentThreadID\n "
},
{
"path": "examples/classic/chat/store/index.js",
"chars": 627,
"preview": "import { createStore, createLogger } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './action"
},
{
"path": "examples/classic/chat/store/mutations.js",
"chars": 1593,
"preview": "export default {\n receiveAll (state, messages) {\n let latestMessage\n messages.forEach(message => {\n // creat"
},
{
"path": "examples/classic/counter/Counter.vue",
"chars": 566,
"preview": "<template>\n <div id=\"app\">\n Clicked: {{ $store.state.count }} times, count is {{ evenOrOdd }}.\n <button @click=\"i"
},
{
"path": "examples/classic/counter/app.js",
"chars": 163,
"preview": "import { createApp } from 'vue'\nimport Counter from './Counter.vue'\nimport store from './store'\n\nconst app = createApp(C"
},
{
"path": "examples/classic/counter/index.html",
"chars": 325,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex counter example</title>\n <link r"
},
{
"path": "examples/classic/counter/store.js",
"chars": 1299,
"preview": "import { createStore } from 'vuex'\n\n// root state object.\n// each Vuex instance is just a single state tree.\nconst state"
},
{
"path": "examples/classic/counter-hot/CounterControls.vue",
"chars": 617,
"preview": "<template>\n <div>\n Value: {{ count }}\n <button @click=\"increment\">+</button>\n <button @click=\"decrement\">-</bu"
},
{
"path": "examples/classic/counter-hot/app.js",
"chars": 187,
"preview": "import { createApp } from 'vue'\nimport store from './store'\nimport CounterControls from './CounterControls.vue'\n\nconst a"
},
{
"path": "examples/classic/counter-hot/index.html",
"chars": 329,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex counter example</title>\n <link r"
},
{
"path": "examples/classic/counter-hot/store/actions.js",
"chars": 364,
"preview": "export const increment = ({ commit }) => {\n commit('increment')\n}\nexport const decrement = ({ commit }) => {\n commit('"
},
{
"path": "examples/classic/counter-hot/store/getters.js",
"chars": 139,
"preview": "export const count = state => state.count\n\nexport const recentHistory = state => {\n return state.history\n .slice(-5)"
},
{
"path": "examples/classic/counter-hot/store/index.js",
"chars": 548,
"preview": "import { createStore } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport * as"
},
{
"path": "examples/classic/counter-hot/store/mutations.js",
"chars": 177,
"preview": "export const increment = state => {\n state.count++\n state.history.push('increment')\n}\n\nexport const decrement = state "
},
{
"path": "examples/classic/shopping-cart/api/shop.js",
"chars": 720,
"preview": "/**\n * Mocking client-server processing\n */\nconst _products = [\n { 'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'i"
},
{
"path": "examples/classic/shopping-cart/app.js",
"chars": 200,
"preview": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { currency } f"
},
{
"path": "examples/classic/shopping-cart/components/App.vue",
"chars": 337,
"preview": "<template>\n <div id=\"app\">\n <h1>Shopping Cart Example</h1>\n <hr>\n <h2>Products</h2>\n <ProductList/>\n <hr"
},
{
"path": "examples/classic/shopping-cart/components/ProductList.vue",
"chars": 674,
"preview": "<template>\n <ul>\n <li\n v-for=\"product in products\"\n :key=\"product.id\">\n {{ product.title }} - {{ curr"
},
{
"path": "examples/classic/shopping-cart/components/ShoppingCart.vue",
"chars": 978,
"preview": "<template>\n <div class=\"cart\">\n <h2>Your Cart</h2>\n <p v-show=\"!products.length\">\n <i>Please add some produc"
},
{
"path": "examples/classic/shopping-cart/currency.js",
"chars": 715,
"preview": "const digitsRE = /(\\d{3})(?=\\d)/g\n\nexport function currency (value, currency, decimals) {\n value = parseFloat(value)\n "
},
{
"path": "examples/classic/shopping-cart/index.html",
"chars": 337,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex shopping cart example</title>\n <"
},
{
"path": "examples/classic/shopping-cart/store/index.js",
"chars": 310,
"preview": "import { createStore, createLogger } from 'vuex'\nimport cart from './modules/cart'\nimport products from './modules/produ"
},
{
"path": "examples/classic/shopping-cart/store/modules/cart.js",
"chars": 2229,
"preview": "import shop from '../../api/shop'\nimport nested from './nested'\n\n// initial state\n// shape: [{ id, quantity }]\nconst sta"
},
{
"path": "examples/classic/shopping-cart/store/modules/nested.js",
"chars": 137,
"preview": "export default {\n namespaced: true,\n state: () => ({\n foo: 'bar'\n }),\n getters: {\n twoBars: state => state.foo"
},
{
"path": "examples/classic/shopping-cart/store/modules/products.js",
"chars": 598,
"preview": "import shop from '../../api/shop'\n\n// initial state\nconst state = () => ({\n all: []\n})\n\n// getters\nconst getters = {}\n\n"
},
{
"path": "examples/classic/todomvc/app.js",
"chars": 162,
"preview": "import { createApp } from 'vue'\nimport store from './store'\nimport App from './components/App.vue'\n\nconst app = createAp"
},
{
"path": "examples/classic/todomvc/components/App.vue",
"chars": 2493,
"preview": "<style src=\"todomvc-app-css/index.css\"></style>\n\n<template>\n <section class=\"todoapp\">\n <!-- header -->\n <header "
},
{
"path": "examples/classic/todomvc/components/TodoItem.vue",
"chars": 1484,
"preview": "<template>\n <li class=\"todo\" :class=\"{ completed: todo.done, editing }\">\n <div class=\"view\">\n <input class=\"tog"
},
{
"path": "examples/classic/todomvc/index.html",
"chars": 278,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex todomvc example</title>\n </head>\n "
},
{
"path": "examples/classic/todomvc/store/actions.js",
"chars": 658,
"preview": "export default {\n addTodo ({ commit }, text) {\n commit('addTodo', {\n text,\n done: false\n })\n },\n\n rem"
},
{
"path": "examples/classic/todomvc/store/index.js",
"chars": 307,
"preview": "import { createStore } from 'vuex'\nimport { mutations, STORAGE_KEY } from './mutations'\nimport actions from './actions'\n"
},
{
"path": "examples/classic/todomvc/store/mutations.js",
"chars": 489,
"preview": "export const STORAGE_KEY = 'todos-vuejs'\n\n// for testing\nif (navigator.webdriver) {\n window.localStorage.clear()\n}\n\nexp"
},
{
"path": "examples/classic/todomvc/store/plugins.js",
"chars": 357,
"preview": "import { createLogger } from 'vuex'\nimport { STORAGE_KEY } from './mutations'\n\nconst localStoragePlugin = store => {\n s"
},
{
"path": "examples/composition/chat/api/index.js",
"chars": 454,
"preview": "const data = require('./mock-data')\nconst LATENCY = 16\n\nexport function getAllMessages (cb) {\n setTimeout(() => {\n c"
},
{
"path": "examples/composition/chat/api/mock-data.js",
"chars": 1397,
"preview": "module.exports = [\n {\n id: 'm_1',\n threadID: 't_1',\n threadName: 'Jing and Bill',\n authorName: 'Bill',\n "
},
{
"path": "examples/composition/chat/app.js",
"chars": 234,
"preview": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { getAllMessag"
},
{
"path": "examples/composition/chat/components/App.vue",
"chars": 384,
"preview": "<style src=\"../css/chat.css\"></style>\n\n<template>\n <div class=\"chatapp\">\n <thread-section></thread-section>\n <mes"
},
{
"path": "examples/composition/chat/components/Message.vue",
"chars": 451,
"preview": "<template>\n <li class=\"message-list-item\">\n <h5 class=\"message-author-name\">{{ message.authorName }}</h5>\n <div c"
},
{
"path": "examples/composition/chat/components/MessageSection.vue",
"chars": 1350,
"preview": "<template>\n <div class=\"message-section\">\n <h3 class=\"message-thread-heading\">{{ thread.name }}</h3>\n <ul class=\""
},
{
"path": "examples/composition/chat/components/Thread.vue",
"chars": 569,
"preview": "<template>\n <li\n class=\"thread-list-item\"\n :class=\"{ active }\"\n @click=\"$emit('switch-thread', thread.id)\">\n "
},
{
"path": "examples/composition/chat/components/ThreadSection.vue",
"chars": 935,
"preview": "<template>\n <div class=\"thread-section\">\n <div class=\"thread-count\">\n <span v-show=\"unreadCount\">\n Unrea"
},
{
"path": "examples/composition/chat/css/chat.css",
"chars": 1977,
"preview": "/**\n * This file is provided by Facebook for testing and evaluation purposes\n * only. Facebook reserves all rights not e"
},
{
"path": "examples/composition/chat/index.html",
"chars": 371,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex chat example</title>\n <link href"
},
{
"path": "examples/composition/chat/store/actions.js",
"chars": 390,
"preview": "import * as api from '../api'\n\nexport const getAllMessages = ({ commit }) => {\n api.getAllMessages(messages => {\n co"
},
{
"path": "examples/composition/chat/store/getters.js",
"chars": 680,
"preview": "export const threads = state => state.threads\n\nexport const currentThread = state => {\n return state.currentThreadID\n "
},
{
"path": "examples/composition/chat/store/index.js",
"chars": 627,
"preview": "import { createStore, createLogger } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './action"
},
{
"path": "examples/composition/chat/store/mutations.js",
"chars": 1593,
"preview": "export default {\n receiveAll (state, messages) {\n let latestMessage\n messages.forEach(message => {\n // creat"
},
{
"path": "examples/composition/counter/Counter.vue",
"chars": 816,
"preview": "<template>\n <div id=\"app\">\n Clicked: {{ count }} times, count is {{ evenOrOdd }}.\n <button @click=\"increment\">+</"
},
{
"path": "examples/composition/counter/app.js",
"chars": 163,
"preview": "import { createApp } from 'vue'\nimport Counter from './Counter.vue'\nimport store from './store'\n\nconst app = createApp(C"
},
{
"path": "examples/composition/counter/index.html",
"chars": 329,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex counter example</title>\n <link r"
},
{
"path": "examples/composition/counter/store.js",
"chars": 1299,
"preview": "import { createStore } from 'vuex'\n\n// root state object.\n// each Vuex instance is just a single state tree.\nconst state"
},
{
"path": "examples/composition/counter-hot/CounterControls.vue",
"chars": 873,
"preview": "<template>\n <div>\n Value: {{ count }}\n <button @click=\"increment\">+</button>\n <button @click=\"decrement\">-</bu"
},
{
"path": "examples/composition/counter-hot/app.js",
"chars": 187,
"preview": "import { createApp } from 'vue'\nimport store from './store'\nimport CounterControls from './CounterControls.vue'\n\nconst a"
},
{
"path": "examples/composition/counter-hot/index.html",
"chars": 333,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex counter example</title>\n <link r"
},
{
"path": "examples/composition/counter-hot/store/actions.js",
"chars": 364,
"preview": "export const increment = ({ commit }) => {\n commit('increment')\n}\nexport const decrement = ({ commit }) => {\n commit('"
},
{
"path": "examples/composition/counter-hot/store/getters.js",
"chars": 302,
"preview": "export const count = state => state.count\n\nexport const t = (state) => {\n return state.test\n}\n\nconst limit = 5\n\nexport "
},
{
"path": "examples/composition/counter-hot/store/index.js",
"chars": 559,
"preview": "import { createStore } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport * as"
},
{
"path": "examples/composition/counter-hot/store/mutations.js",
"chars": 177,
"preview": "export const increment = state => {\n state.count++\n state.history.push('increment')\n}\n\nexport const decrement = state "
},
{
"path": "examples/composition/shopping-cart/api/shop.js",
"chars": 593,
"preview": "/**\n * Mocking client-server processing\n */\nconst _products = [\n { 'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'i"
},
{
"path": "examples/composition/shopping-cart/app.js",
"chars": 162,
"preview": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\n\nconst app = createAp"
},
{
"path": "examples/composition/shopping-cart/components/App.vue",
"chars": 337,
"preview": "<template>\n <div id=\"app\">\n <h1>Shopping Cart Example</h1>\n <hr>\n <h2>Products</h2>\n <ProductList/>\n <hr"
},
{
"path": "examples/composition/shopping-cart/components/ProductList.vue",
"chars": 1012,
"preview": "<template>\n <ul>\n <li\n v-for=\"product in products\"\n :key=\"product.id\">\n {{ product.title }} - {{ curr"
},
{
"path": "examples/composition/shopping-cart/components/ShoppingCart.vue",
"chars": 1126,
"preview": "<template>\n <div class=\"cart\">\n <h2>Your Cart</h2>\n <p v-show=\"!products.length\">\n <i>Please add some produc"
},
{
"path": "examples/composition/shopping-cart/currency.js",
"chars": 715,
"preview": "const digitsRE = /(\\d{3})(?=\\d)/g\n\nexport function currency (value, currency, decimals) {\n value = parseFloat(value)\n "
},
{
"path": "examples/composition/shopping-cart/index.html",
"chars": 341,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex shopping cart example</title>\n <"
},
{
"path": "examples/composition/shopping-cart/store/index.js",
"chars": 310,
"preview": "import { createStore, createLogger } from 'vuex'\nimport cart from './modules/cart'\nimport products from './modules/produ"
},
{
"path": "examples/composition/shopping-cart/store/modules/cart.js",
"chars": 2139,
"preview": "import shop from '../../api/shop'\n\n// initial state\n// shape: [{ id, quantity }]\nconst state = {\n items: [],\n checkout"
},
{
"path": "examples/composition/shopping-cart/store/modules/products.js",
"chars": 582,
"preview": "import shop from '../../api/shop'\n\n// initial state\nconst state = {\n all: []\n}\n\n// getters\nconst getters = {}\n\n// actio"
},
{
"path": "examples/composition/todomvc/app.js",
"chars": 162,
"preview": "import { createApp } from 'vue'\nimport store from './store'\nimport App from './components/App.vue'\n\nconst app = createAp"
},
{
"path": "examples/composition/todomvc/components/App.vue",
"chars": 2738,
"preview": "<style src=\"todomvc-app-css/index.css\"></style>\n\n<template>\n <section class=\"todoapp\">\n <!-- header -->\n <header "
},
{
"path": "examples/composition/todomvc/components/TodoItem.vue",
"chars": 1576,
"preview": "<template>\n <li class=\"todo\" :class=\"{ completed: todo.done, editing }\">\n <div class=\"view\">\n <input class=\"tog"
},
{
"path": "examples/composition/todomvc/index.html",
"chars": 282,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>vuex todomvc example</title>\n </head>\n "
},
{
"path": "examples/composition/todomvc/store/actions.js",
"chars": 658,
"preview": "export default {\n addTodo ({ commit }, text) {\n commit('addTodo', {\n text,\n done: false\n })\n },\n\n rem"
},
{
"path": "examples/composition/todomvc/store/index.js",
"chars": 307,
"preview": "import { createStore } from 'vuex'\nimport { mutations, STORAGE_KEY } from './mutations'\nimport actions from './actions'\n"
},
{
"path": "examples/composition/todomvc/store/mutations.js",
"chars": 489,
"preview": "export const STORAGE_KEY = 'todos-vuejs'\n\n// for testing\nif (navigator.webdriver) {\n window.localStorage.clear()\n}\n\nexp"
},
{
"path": "examples/composition/todomvc/store/plugins.js",
"chars": 357,
"preview": "import { createLogger } from 'vuex'\nimport { STORAGE_KEY } from './mutations'\n\nconst localStoragePlugin = store => {\n s"
},
{
"path": "examples/global.css",
"chars": 325,
"preview": "html, body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple "
},
{
"path": "examples/index.html",
"chars": 943,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>Vuex Examples</title>\n <link rel=\"sty"
},
{
"path": "examples/server.js",
"chars": 728,
"preview": "const express = require('express')\nconst webpack = require('webpack')\nconst webpackDevMiddleware = require('webpack-dev-"
},
{
"path": "examples/webpack.config.js",
"chars": 1646,
"preview": "const fs = require('fs')\nconst path = require('path')\nconst webpack = require('webpack')\nconst { VueLoaderPlugin } = req"
},
{
"path": "jest.config.js",
"chars": 587,
"preview": "module.exports = {\n rootDir: __dirname,\n testEnvironment: 'jsdom',\n globals: {\n __DEV__: true\n },\n moduleNameMap"
},
{
"path": "package.json",
"chars": 3144,
"preview": "{\n \"name\": \"vuex\",\n \"version\": \"4.1.0\",\n \"description\": \"state management for Vue.js\",\n \"main\": \"dist/vuex.cjs.js\",\n"
},
{
"path": "rollup.config.js",
"chars": 2585,
"preview": "import buble from '@rollup/plugin-buble'\nimport replace from '@rollup/plugin-replace'\nimport resolve from '@rollup/plugi"
},
{
"path": "scripts/build.js",
"chars": 1174,
"preview": "const fs = require('fs-extra')\nconst chalk = require('chalk')\nconst execa = require('execa')\nconst { gzipSync } = requir"
},
{
"path": "scripts/release.js",
"chars": 3005,
"preview": "const fs = require('fs')\nconst path = require('path')\nconst chalk = require('chalk')\nconst semver = require('semver')\nco"
},
{
"path": "src/helpers.js",
"chars": 6589,
"preview": "import { isObject } from './util'\n\n/**\n * Reduce the code which written in Vue.js for getting the state.\n * @param {Stri"
},
{
"path": "src/index.cjs.js",
"chars": 434,
"preview": "import { Store, createStore } from './store'\nimport { storeKey, useStore } from './injectKey'\nimport { mapState, mapMuta"
},
{
"path": "src/index.js",
"chars": 592,
"preview": "import { Store, createStore } from './store'\nimport { storeKey, useStore } from './injectKey'\nimport { mapState, mapMuta"
},
{
"path": "src/index.mjs",
"chars": 424,
"preview": "import Vuex from '../dist/vuex.cjs.js'\n\nconst {\n version,\n Store,\n storeKey,\n createStore,\n install,\n useStore,\n "
},
{
"path": "src/injectKey.js",
"chars": 152,
"preview": "import { inject } from 'vue'\n\nexport const storeKey = 'store'\n\nexport function useStore (key = null) {\n return inject(k"
},
{
"path": "src/module/module-collection.js",
"chars": 3497,
"preview": "import Module from './module'\nimport { assert, forEachValue } from '../util'\n\nexport default class ModuleCollection {\n "
},
{
"path": "src/module/module.js",
"chars": 1612,
"preview": "import { forEachValue } from '../util'\n\n// Base data struct for store's module, package with some attribute and method\ne"
},
{
"path": "src/plugins/devtool.js",
"chars": 7729,
"preview": "import { setupDevtoolsPlugin } from '@vue/devtools-api'\nimport { makeLocalGetters } from '../store-util'\n\nconst LABEL_VU"
},
{
"path": "src/plugins/logger.js",
"chars": 2530,
"preview": "// Credits: borrowed code from fcomb/redux-logger\n\nimport { deepCopy } from '../util'\n\nexport function createLogger ({\n "
},
{
"path": "src/store-util.js",
"chars": 8560,
"preview": "import { reactive, computed, watch, effectScope } from 'vue'\nimport { forEachValue, isObject, isPromise, assert, partial"
},
{
"path": "src/store.js",
"chars": 7310,
"preview": "import { watch } from 'vue'\nimport { storeKey } from './injectKey'\nimport { addDevtools } from './plugins/devtool'\nimpor"
},
{
"path": "src/util.js",
"chars": 1538,
"preview": "/**\n * Get the first item that pass the test\n * by second argument function\n *\n * @param {Array} list\n * @param {Functio"
},
{
"path": "test/.eslintrc.json",
"chars": 36,
"preview": "{\n \"env\": {\n \"jest\": true\n }\n}\n"
},
{
"path": "test/e2e/cart.spec.js",
"chars": 1717,
"preview": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/cart', () => {\n const { page, text, count, cl"
},
{
"path": "test/e2e/chat.spec.js",
"chars": 1860,
"preview": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/chat', () => {\n const { page, text, count, cl"
},
{
"path": "test/e2e/counter.spec.js",
"chars": 1208,
"preview": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/counter', () => {\n const { page, text, click,"
}
]
// ... and 22 more files (download for full content)
About this extraction
This page contains the full source code of the vuejs/vuex GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 222 files (512.2 KB), approximately 156.7k tokens, and a symbol index with 330 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.