ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
**vuex** [[vue官方网站 vuex]](https://vuex.vuejs.org/) 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. ---- [TOC] ---- ## Introduction 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://vuejs.org/v2/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. ---- 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! ![vuex](https://box.kancloud.cn/288a0dc913bab3fe765baf18fb4bac27_701x551.png) ## 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://vuejs.org/v2/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. ## Installation ### Direct Download / CDN [https://unpkg.com/vuex](https://unpkg.com/vuex) [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@2.0.0`. Include`vuex`after Vue and it will install itself automatically: ~~~ <script src="/path/to/vue.js"></script> <script src="/path/to/vuex.js"></script> ~~~ ### NPM/Yarn NPM ~~~bash npm install vuex --save ~~~ Yarn ~~~bash yarn add vuex ~~~ When used with a module system, you must explicitly install Vuex via`Vue.use()`: ~~~javascript import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) ~~~ You don't need to do this when using global script tags. ## The Simplest Store > **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 Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations: ~~~javascript // Make sure to call Vue.use(Vuex) first if using a module system const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) ~~~ Now, you can access the state object as`store.state`, and trigger a state change with the`store.commit`method: ~~~javascript store.commit('increment') console.log(store.state.count) // -> 1 ~~~ 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. ## Concept ### State 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. 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): ~~~javascript // 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 provides a mechanism to "inject" the "store" into all child components from the root component with the`store`option (enabled by`Vue.use(Vuex)`): ~~~javascript const app = new Vue({ el: '#app', // provide the store using the "store" option. // this will inject the store instance to all child components. store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` }) ~~~ By providing the`store`option to the root instance, the store will be injected into all child components of the root and will be available on them as`this.$store`. Let's update our`Counter`implementation: ~~~javascript const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } } ~~~ ### getters ### mutations ### actions ## Application Structure [[官方文档]](https://vuex.vuejs.org/guide/structure.html) 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: ~~~txt ├── 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 ~~~ >[warning] vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的`namespaced:true`,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名 As a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart).