Learn about Vuex systematically

What is 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 way (reactive change).

What is the "State Management Pattern"?

Let's start with a simple Vue counting app:

new Vue({
    
    
  // state
  data () {
    
    
    return {
    
    
      count: 0
    }
  },
  // view
  template: `
    <div>{
     
     { count }}</div>
  `,
  // actions
  methods: {
    
    
    increment () {
    
    
      this.count++
    }
  }
})

This stateful self-managing application consists of the following parts:

  • state, the data source driving the application;
  • view, which declaratively maps state to a view;
  • actions, which respond to state changes caused by user input on the view.

The following is a simple representation of the concept of "one-way data flow":
insert image description here
the state data will be displayed on the view, and the user will operate according to the content on the view, thereby triggering actions, and then affecting the state (vue is one-way data flow-driven).

However, the simplicity of unidirectional data flow can easily be broken when our application encounters multiple components sharing state:

  • Multiple views depend on the same state.
  • Actions from different views need to mutate the same state.

For problem 1, the method of passing parameters will be very cumbersome for multi-layer nested components, and it can't do anything about state transfer between sibling components.
For problem two, we often use parent-child components to directly reference or use events to change and synchronize multiple copies of the state. These patterns above are very brittle and often lead to unmaintainable code.

So, why don't we extract the shared state of the components and manage it in a global singleton mode? In this mode, our component tree constitutes a huge "view", no matter where it is in the tree, any component can get state or trigger behavior!

The following figure extracts the shared state of components and manages them in a global singleton mode.
insert image description here


Application scenarios of Vuex

1. Multiple views depend on the same state (reading), such as token, user information, etc. (data persistence processing is required)

2. Behavior from different views needs to change the same state (write)


Vuex installation

vue2.0 can only install vuex3.x version, up to 3.6.2; vue3.0 can only install vuex4.x version
npm install [email protected] --save

With Vuex installed, let's create a store.
insert image description here

//store/index.js
// 初始化一个vuex的实例(数据仓库) 导出即可
import Vuex from 'vuex'
import Vue from 'vue'
// 使用安装
Vue.use(Vuex)
 
// 初始化
const store = new Vuex.Store({
    
    
  // 配置(state|getter|mutations|actions)
  state: {
    
    },
  getters: {
    
    },
  mutations: {
    
    },
  actions: {
    
    }
})
 
export default store
//main.js
+import store from '@/store'
 
new Vue({
    
    
+  store,
  render: h => h(App),
}).$mount('#app')

Composition of Vuex

  1. State: data warehouse;
    State itself means data, and it represents the source of data in Vuex. All data in Vuex will be stored in State, which is the only source of data.
  2. Getter: Used to get data;
    it can be considered as a computed property of store, just like computed computed property, the return value of getter will be cached according to its dependencies, and will only be recalculated when its dependent value changes .
  3. Mutation: used to modify data;
    (1) Mutation is essentially a function.
    (2) The operation of Mutation must be synchronous . If it is asynchronous, there will be a lot of trouble. The official explanation is quoted below:
    insert image description here
  • The main reason why mutation cannot be asynchronous is for debugging , not for not being able to modify the state.
  1. Action: used to submit mutations, which can perform asynchronous operations.

State

  • define data
// 初始化vuex对象
const store = new vuex.Store({
    
    
  state: {
    
    
    // 管理数据
    count: 0
  }
})
  • use data

1). Use this directly

<div>A组件 state的数据:{
    
    {
    
    $store.state.count}}</div>
...
created () {
    
    
    console.log(this.$store.state.count)
}

2). Used in the computed option

computed: {
    
    
    count () {
    
    
        return this.$store.state.count
    }
}

3). Use mapState auxiliary function

import {
    
     mapState } from vuex
...
computed: {
    
    
    ...mapState(['count'])
    // 将一个 state 属性另取一个名字,使用对象形式:
    // ...mapState({ newCount: 'count' })
}
...
<div>A组件 state的数据:{
    
    {
    
    count}}</div>

Getter

  • Define getters data (understood as computed properties in vuex)
const store = new vuex.Store({
    
    
  	state: {
    
    
	  count: 10
	},
	// 基于state得到一个新数据
	getters: {
    
    
	  newCount (state) {
    
    
	    return state.count++
	  }
	}    
})
  • use getters data

1). Use this directly

this.$store.getters.newCount
...
<div>{
    
    {
    
    $store.getters.newCount}}</div>

2). Used in computed

<div>{
    
    {
    
    newCount}}</div>
...
computed: {
    
    
  newCount() {
    
    
    return this.$store.getters.newCount
  }  
}

3). Use of mapGetters auxiliary function

import {
    
     mapGetters } from vuex
...
computed: {
    
    
  ...mapGetters(['newCount']) 
  // 将一个 getter 属性另取一个名字,使用对象形式:
  // ...mapGetters({ count: 'newCount' }) 
},
...
<div>{
    
    {
    
    newCount}}</div>

Mutation

  • Define the mutations function
const store = new vuex.Store({
    
    
  state: {
    
    
    count: 0
  },
  mutations: {
    
    
    // 修改数据的函数  
    add (state) {
    
    
      state.count ++
    },
    // 带参数修改数据的函数
    add2 (state, payload) {
    
    
      // payload 是传参的意思
      state.count += payload  
    }  
  }
})
  • Using the mutations function

1). Use this directly

this.$store.commit('add')
this.$store.commit('add2', 10)

2). The mapMutations auxiliary function is used

import {
    
     mapMutations } from vuex
...
methods: {
    
    
  ...mapMutations(['add','add2'])
  // ...mapMutations({ myadd: 'add' })
}
...
<button @click="add">累加1</button>
<button @click="add2(10)">累加10</button>

Action

  • Define the actions function
actions: {
    
    
  // 异步获取数据  
  getData ({
     
     commit}, payload) {
    
    
    setTimeout(()=>{
    
    
	  const data = 100
      // 通过mutations修改数据
      commit('add2', data)
    },1000)
  }
}
  • Use the actions function

1). Use this directly

this.$store.dispatch('getData')

2). mapActions helper function use

import {
    
     mapActions } from vuex
...
methods: {
    
    
  ...mapActions(['getData'])
  // ...mapActions({ getMyData: 'getData' })
}
...
<button @click="getData">获取数据</button>

Module

Due to the use of a single state tree, all the state of the application will be concentrated into a relatively large object. When the application becomes very complex, the store object can become quite bloated.
To solve the above problems, Vuex allows us to split the store into modules. Each module has its own state, mutation, action, getter.
When using vuex, if you use module, how to distinguish each module, you need to use namespace

// moduleA模块:
export default {
    
    
  namespaced:true,
  state:{
    
    
    msg: '我是moduleA中的数据',
    num: 0
  },
  getters:{
    
    
    msg:state=>state.msg,
    num:state=>state.num
  },
  mutations:{
    
    
    ['ADD_FUN'](state){
    
    
      return state.num++;
    }
  },
  actions:{
    
    
  }
};

// moduleB模块:
export default {
    
    
  namespaced:true,
  state:{
    
    
    msg:'我是moduleB中的msg'
  },
  getters:{
    
    
    msg:state=>state.msg
  },
  mutations:{
    
    },
  actions:{
    
    }
};

store/index.jsRegister the module in

import Vue from 'vue'
import Vuex from 'vuex'
import moduleA from './moduleA'
import moduleB from './moduleB'

Vue.use(Vuex)

export default new Vuex.Store({
    
    
  modules:{
    
    
    // 放每个模块对应的小store
    moduleA,
    moduleB
  }
})

Use module data that adds a namespace

import {
    
     mapGetters, mapMutations } from 'vuex'
export default {
    
    
  computed: {
    
    
    ...mapGetters('moduleA',['msg','num']),
  },
  methods: {
    
    
    ...mapMutations('moduleB',['ADD_FUN'])
  },
}
  • Summary: The use of the vuex module namespace is mainly added namespaced:trueto each module. When using it, ...mapGetters('模块名',['msg'])you can use it through Tathagata.

Vuex data persistence

The data in vuex will be initialized when the page is refreshed, so it can be introduced vuex-persistedstatefor data persistence. The principle is to store vuex data in localstorage, but the operation process is simplified.

Install vuex-persistedstate

npm install --save vuex-persistedstate

Specific use

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from "vuex-persistedstate"
import moduleA from './moduleA'
Vue.use(Vuex)
const store = new Vuex.Store({
    
    
  state: {
    
    ...},
  getters: {
    
    ...},
  mutations: {
    
    ...},
  actions: {
    
    ...},
  modules: {
    
    ...},
  /* vuex数据持久化配置 */
  // 默认会将vuex数据全部持久化
  // plugins: [createPersistedState()]
  // 按模块引入
  createPersistedState({
    
    
     // 存储方式:localStorage、sessionStorage、cookies
     // storage: window.sessionStorage,
     // 存储的 key 的key值
     // key: "user",
     paths: ['moduleA']
   })
})

Vuex official website:https://vuex.vuejs.org/zh/installation.html
vuex-persistedstate:https://github.com/robinvdvleuten/vuex-persistedstate

Guess you like

Origin blog.csdn.net/weixin_42566993/article/details/126084941