As an important member of the vue family bucket, we often use vuex in the vue construction project.
About VueX
Vuex is a state management pattern** developed specifically for Vue.js applications . It uses a centralized storage to manage the state of all components of the application, and uses corresponding rules to ensure that the state changes in a predictable manner.
VueX is a state management tool suitable for use in Vue project development. Just imagine, if you frequently use component passing parameters to synchronize the values in data in a project development, once the project becomes very large, managing and maintaining these values will be quite a tricky job. To this end, Vue provides a unified management tool for these values frequently used by multiple components - VueX. In a Vue project with VueX, we only need to define these values in VueX to be used in components of the entire Vue project.
Why use vuex
For example: you have several data and several operations that need to be used on multiple components. If each component is called and written, it will be very troublesome, and the code is cumbersome and long. It’s easy to mess up in use. At this time, if we use vuex for unified management, it will be very convenient to manage, and it will be more convenient and concise to modify data.
When should I use Vuex?
Vuex can help us manage shared state and comes with more concepts and frameworks. This requires a trade-off between short-term and long-term benefits.
Using Vuex can be tedious and redundant if you're not planning to develop a large single-page application. It's true - if your application is simple enough, you'd better not use Vuex. A simple store pattern is all you need. However, if you need to build a medium-to-large single-page application, you are likely to consider how to better manage the state outside the component, and Vuex will become a natural choice.
There is no way to share data between vuex components
Passing value from parent to child: v-bind attribute binding
Passing values from child to parent: v-on event binding
Data sharing between sibling components: EventBus
- $on The component that receives the data
- $emit The component that sends data
The benefits of using Vuex to manage state uniformly
Vuex is a mechanism to realize the global state (data) management of components, which can facilitate the sharing of data between components.
1. It can centrally manage shared data in vuex, which is easy to develop and maintain later
2. It can efficiently realize data sharing between components and improve development efficiency
3. The data stored in vuex is responsive and can keep the data and page in real time
What is stored in vuex
Multiple components share state and store it in vuex
Private data in a component is still stored in data
For example:
- The login user name needs to be used on the home page , personal center , and settlement page, and the user name is stored in vuex
- The article details data can only be viewed on the article details page, and declared in its own data
Basic use of Vuex
1. Install vuex
npm i vuex -S
2.store/index.js - create a definition export store object
Registered in Vue, the function is also an object, you can also point attributes
new A Vuex Store data warehouse
// 1. 引入vuex
import Vuex from 'vuex'
// 2. Vue.use注册使用
Vue.use(Vuex)
// 3. 实例化store对象 这个store对我们的状态进行管理
const store = new Vuex.Store({
//4.
})
// 5. 导出store对象
export default store
3. Mount the store to the Vue instance of the current project
Import store into main.js
import store from './store'
Vue.config.productionTip = false
new Vue({
// 注入到vue实例中
store, //store:store将我们创建的Vuex实例挂载到这个vue实例中
render: h => h(App),
}).$mount('#app')
4. Using Vuex in components
For example, in App.vue, we want to display the name defined in the state in the h1 tag
<template>
<div id='app'>
name:
<h1>{
{
$store.state.name }}</h1>
</div>
</template>
Use of data sources:
It can only be used and mapped directly within the component (the file ending in .APP is a component) (auxiliary function)
In the file ending with the .js suffix, you need to import and use
import store from '@/store' //引入
store.state.token //使用
state data source
State provides the only public data source, and all shared data must be stored in the State of the Store.
define state
/*语法格式
const store = new Vuex.Store({
state: {
变量名: 初始值
}
})
*/
//具体代码:
const store = new Vuex.Store({
state: {
count: 100 // 库存
}
})
There are 2 ways to use state:
1. The first way for a component to access data in State : within the component - direct use
// this.$store.state.全局数据名称
this.$store.state.count
2. The second way for components to access data in State : within components - mapping (recommended)
// 1. 拿到mapState辅助函数
import {
mapState } from 'vuex'
export default {
computed: {
// 2. 把state里变量映射到计算属性中
...mapState(['count']) //count就是state里的变量名
}
}
Through the mapState function imported just now, the global data required by the current component will be transferred. Mapped to the computed property of the current component:
<template>
<div>
<h3>方法一:当前最新的count值:{
{
$store.state.count}}</h3>
<h3>方法二-03:当前最新的count值:{
{
count}}</h3>
<button>+1</button>
</div>
</template>
<script>
import {
mapState } from 'vuex' //方法二-01
export default {
computed: {
//方法二-02
...mapState(['count'])
}
}
</script>
Notice
The state is responsive, as long as the state value changes, the places used on the page will be automatically updated and synchronized
summary
-
State role?
Define a global state data source
-
How is state defined?
In store, state: {variable name: initial value}
-
How to use the value of state in specific vue components?
- Use this.$store.state. variable name directly
- Mapping uses...mapState(['state variable name'])
mutations - synchronous modification
Mutations are similar to data stewards, manipulating the data in the state
Define mutations in store/index.js
grammar:
/*
const store = new Vuex.Store({
mutations: {
函数名 (state, 可选值) {
// 同步修改state值代码
}
}
})
*/
Reference Code
const store = new Vuex.Store({
state: {
count: 100 // 库存
},
mutations: {
addCount (state, value) {
// 负责增加库存的管家
state.count += value
},
subCount (state, value) {
// 负责减少库存的管家
state.count -= value
},
setCount (state, value) {
// 负责直接修改库存的管家
state.count = value;
}
}
})
Notice
- Mutations are the only place where state can be modified, ensuring that debugging tools can track changes
- In the mutations function, only synchronous code can be written, and the debugging tool can track the change process
- Because the debugging tool needs to generate a record immediately , it must be synchronous
summary
-
Functions in mutations?
- Responsible for modifying the data in the state
-
What kind of code can only be written in mutations?
- code for synchronous process
2 ways to use mutations
-
Method 1: Inside the component - use d directly
grammar:
this.$store.commit("mutations里的函数名", 具体值)
-
Method 2: In-component- mapping usage
grammar:
// 1. 拿到mapMutations辅助函数 import { mapMutations } from 'vuex' export default { methods: { // 2. 把mutations里方法映射到原地 ...mapMutations(['mutations里的函数名']) } }
AddItem directly use
- Click event binding
- Submit mutations incoming values
<button @click="addFn">库存+1</button>
<script>
export default {
methods: {
addFn(){
this.$store.commit('addCount', 1)
}
}
}
</script>
App.vue is used directly
- Trigger the set method of the computed property
- Submit mutations incoming values
<span>库存总数: </span>
<input type="text" v-model="count">
<script>
export default {
computed: {
count: {
set(val){
this.$store.commit('setCount', val) // 把表单值提交给store下的mutations
},
get(){
return this.$store.state.count
}
}
}
}
</script>
SubItem mapping for
- click event
- Methods for mapping mutations
- Call the mutations method to pass the value
<button @click="subFn">库存-1</button>
<script>
// 需求2: 映射mutations到方法里
// 1. 拿到辅助函数 mapMutations
// 2. 在methods内, ...mapMutations(['mutations函数名'])
// 3. 当普通方法使用
import { mapMutations } from 'vuex'
export default {
methods: {
...mapMutations(['subCount']),
subFn(){
this.subCount(1)
}
}
}
</script>
Notice
On the mutations function, only one parameter value can be received , if the correct one is passed, please pass an object
summary
-
What are the 2 ways to use mutations?
Use this.$store.commit() directly
Mapping uses mapMutations to map methods to direct calls in components
-
state, mutations, view components, what are the 3 relationships?
actions - asynchronous modification
Action is similar to mutation, the difference is:
- Actions submit mutations instead of directly changing the state.
- Action can contain arbitrary asynchronous operations.
If you change data through asynchronous operations, you must use Action instead of Mutation, but you still need to indirectly change data by triggering Mutation in Action.
define actions
Define actions in store/index.js
grammar:
/*
const store = new Vuex.Store({
actions: {
函数名 (store, 可选值) {
// 异步代码, 把结果commit给mutations给state赋值
}
}
})
*/
Specific code:
const store = new Vuex.Store({
// ...省略state和mutations此处
actions: {
asyncAddCount(store, num){
setTimeout(() => {
// 1秒后, 异步提交给add的mutations
store.commit('addCount', num)
}, 1000)
},
asyncSubCount(store, num) {
setTimeout(() => {
// 1秒后, 异步提交给sub的mutations
store.commit('subCount', num)
}, 1000)
}
}
})
summary
-
What is the difference between actions and mutations?
Synchronously modify state in mutations
Put asynchronous operations in actions
-
Can actions manipulate state?
Not recommended, commit to mutations (trackable for debugging tools)
-
What is the first formal parameter of the functions in actions and mutations?
mutations are state
actions are store
2 ways to use actions
-
Method 1: In the component - direct use
grammar:
this.$store.dispatch('actions函数名', 具体值)
-
Method 2: In-component- mapping usage
grammar:
// 1. 拿到mapActions辅助函数 import { mapActions } from 'vuex' export default { methods: { // 2. 把actions里方法映射到原地 ...mapActions(['actions里的函数名']) } }
Case code:
AddItem directly use
- click event
- dispatch triggers action
<button @click="asyncAddFn">延迟1秒, 库存+5</button>
<script>
export default {
methods: {
asyncAddFn(){
this.$store.dispatch('asyncAddCount', 5)
}
}
}
</script>
SubItem mapping for
- click event
- Methods for mapping actions
- Call the method of actions to pass the value
<button @click="asyncSubFn">延迟1秒, 库存-5</button>
<script>
// 需求3: 映射actions到方法里
// 1. 拿到辅助函数 mapActions
// 2. 在methods内, ...mapActions(['actions函数名'])
// 3. 当普通方法使用
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(['asyncSubCount']),
asyncSubFn(){
this.asyncSubCount(5)
}
}
}
</script>
summary
-
How to use actions?
Method 1: this.$store.dispatch('actions method name', value)
Method 2: …mapActions(['method name in actions']) is mapped to in-place use
-
What is the relationship between view components, state, mutations, and actions?
getters - computed properties
concept of getters
computed properties of vuex,
Getter is used to process the data in the Store to form new data.
- 1. Getter is similar to Vue's computed property
- 2. When the data in the Store changes, the Getter data will also change
define getters
Define getters in store/index.js
grammar:
// 定义 Getter
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
getSum: state => {
return `当前的新数据是【${
state}】`
}
}
})
2 ways to use getters
-
Method 1: In the component - direct use
grammar:
//this.$store.getters.计算属性名 this.$store.getters.getSum
-
Method 2: In-component- mapping usage
grammar:
// 1. 拿到mapGetters辅助函数 import { mapGetters } from 'vuex' export default { computed: { // 2. 把getters里属性映射到原地 ...mapGetters(['getSum']) } }
modules- sub-module
When the project is huge and has many states, the modular management mode can be adopted. Vuex allows us to split the store into modules . Each module has its own state、mutation、action、getter
, and even nested, submodules - split the same way from top to bottom.
The following is a comparison between modules and sub-modules:
Create modules module object
- New store/modules/user.js
- New store/modules/cart.js
Grammar: The object contains 5 core concepts, only the state becomes a function form
user.js - the user module object
// 用户模块对象
const userModule = {
state(){
return {
name: "",
age: 0,
sex: ''
}
},
mutations: {
},
actions: {
},
getters: {
}
}
export default userModule
cart.js - shopping cart module object
// 购物车模块对象
import axios from 'axios'
const cartModule = {
state() {
return {
goodsList: []
}
},
mutations: {
setGoodsList(state, newList) {
state.goodsList = newList
}
},
actions: {
async asyncGetGoodsList(store) {
const url = `https://www.escook.cn/api/cart`
// 发送异步请求
const res = await axios({
url: url });
store.commit('setGoodsList', res.data.list) // 提交mutation修改state中的数据
}
},
getters: {
allCount(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state === true) {
// 选中商品才累加数量
sum += obj.goods_count;
}
return sum;
}, 0)
},
allPrice(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state) {
sum += obj.goods_count * obj.goods_price
}
return sum;
}, 0)
}
}
}
export default cartModule
define modules
grammar:
modules: {
模块名: 模块对象
}
- Bring 2 module objects back to the store for registration
import Vue from 'vue'
import Vuex from 'vuex'
import cartModule from './modules/cart'
import userModule from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user: userModule,
cart: cartModule
}
})
export default store
summary
-
Why sub-modules?
The centralized management project is too large and there are too many variables, which will lead to bloated state and difficult maintenance
-
How to divide modules?
Define the module object , the state becomes the function return object form, each module has state/mutations/actions/getters/modules
-
How to register the root store?
In modules { module name: module object }
sub-module-namespace
Target
- Prevent name conflicts of mutations/actions/getters between multiple modules
Enable namespace
set inside the module objectnamespaced: true
const moduleShopCar = {
namespaced: true,
state () {
},
mutations: {
},
actions: {
},
getters: {
},
modules: {
}
}
state usage modification
-
Direct use without change: this.$store.state.module name.variable name
-
Helper functions need to respect the format
...mapState("模块名", ['state变量名'])
mutations usage modification
-
Method 1: In the component - direct use
-
Original syntax:
this.$store.commit("mutations里的函数名", 具体值)
-
Syntax after opening a namespace:
this.$store.commit("模块名/mutations里的函数名", 具体值)
-
-
Method 2: In-component- mapping usage
-
Original syntax:
...mapMutations(['mutations里方法名'])
-
Syntax after opening a namespace:
...mapMutations("模块名", ['mutations里方法名'])
-
Actions usage modification
-
Method 1: In the component - direct use
-
Original syntax:
this.$store.dispatch("actions里的函数名", 具体值)
-
Syntax after opening a namespace:
this.$store.dispatch("模块名/actions里的函数名", 具体值)
-
-
Method 2: In-component- mapping usage
-
Original syntax:
...mapActions(['actions里方法名'])
-
Syntax after opening a namespace:
...mapActions("模块名", ['actions里方法名'])
-
Getters usage modification
-
Method 1: In the component - direct use
-
Original syntax:
this.$store.getters.计算属性名
-
Syntax after opening a namespace:
this.$store.getters['模块名/计算属性名']
-
-
Method 2: In-component- mapping usage
-
Original syntax:
...mapGetters(['getters里计算属性名'])
-
Syntax after opening a namespace:
...mapGetters("模块名", ['getters里计算属性名'])
-
summary
- What is the difference between state and mutations, in the root store and in the open namespace?
-
What is the whole vuex system?
Extension: Use Devtools to debug vuex data
Excellent debugging tools can make us write programs with half the effort. Finally, let's learn how to use dev-tools to debug the data in vuex, which is also an indispensable part of the predictable data feature.
Target
- Master dev-tools debugging vuex
- Understand what data state is traceable
how to debug
Note that only vue+vuex projects can be used