vue foundation V (state management)

Posted by foid025 on Thu, 28 Oct 2021 13:59:37 +0200


vuex is a software developed specifically for Vue.js applications State management mode.
Centralized storage management is adopted to manage the state of all components of the application, and corresponding rules are used to ensure that the state changes in a predictable way.
Vue provides a unified management tool - VueX for these values frequently used by multiple components.
In a Vue project with VueX, we only need to define these values in VueX, which can be used in the components of the whole Vue project.

  • Small projects (not applicable to vuex)
  • Small and medium-sized projects (with store mode)
  • Medium and large projects (vuex can be divided into modules)

State management mode

The state management mode includes the following parts:

  • Data source of state driven application
  • View maps state to view declaratively
  • actions responds to state changes caused by user input on the view
    We extract the shared state of components and manage it in a global singleton mode
    In this mode, our component tree constitutes a huge "view". No matter where in the tree, any component can obtain status or trigger behavior.

Using vuex

Vuex can help manage shared state.

For small and medium-sized projects, which are not particularly large, vuex is relatively redundant, and the store mode can be used.
If you need to build a medium and large-scale single page application, you can use vuex to manage the external state of components.

Simple store mode

Create a new store.js as a temporary warehouse in the utils folder

export default{
    debug:true,
    state:{
        msg:"is store",
        name:'zhangsan'
    },
    actions:{
        getname(){
            console.log('zhangsan');
        }
    }
}

Get the data and methods in the store warehouse in the component
Home.vue

<template>
  <!-- {{state.msg}} -->
  <!-- <button @click="getname">click</button> -->
</template>
<script>
	import store from '../utils/store'
	export default {
	  data(){
	    return{
	      state:store.state
	    }
	  },
	  methods:{
	    ...store.actions
	  }
	}
</script>

Single state tree

vuex uses a single state tree, and one object contains all application level states.
Each application contains only one store instance.
The single state tree allows us to directly locate any specific state fragment, and easily obtain a snapshot of the current application state during debugging.
A single state tree does not conflict with modularization, and state and state change events can be distributed to each sub module.

Installation and use of vuex

Installing vuex

npm i vuex -s

initialization

A new file index.js is added in the store folder

import { createStore } from 'vuex'
export default createStore({
  state: {
  	msg:'is store',
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

Mount the store into the vue instance of the current project

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')

Using vuex in components

State

Store data

state: {
	  	msg:'is store',
	  	...
},

Used in components
Home component

Method 1:

<template>
        {{$store.state.msg}} //Generally, it is not used in this way
</template>

Method 2: attribute calculation method

<template>
        {{msg}}; //Official recommended usage
</template>
<script>
 export default{
  computed:{
  	msg(){
  		return  this.$ store.state.msg; //Officially recommended
  	}
    }
  }
 </script>

Method 3: auxiliary function (common methods in the project)

<template>
        {{msg}}; 
</template>
<script>
import {{mapState}}  from 'vuex'  //auxiliary function 
 export default{
   computed:{
  		...mapState(['msg']),  //Deconstruction data
   },
  }
 </script>

getters

Vuex allows us to define "getter s" (which can be considered as the calculated attributes of the store) in the store.
Just like calculating attributes, (cache after obtaining) the return value of getter will be cached according to its dependency, and will be recalculated only when its dependency value changes.
definition

  state: {
    books:['js01','js02','js03'],
  },
  getters:{
    GET_BOOK_NUM:(state,getters)=>{
      return state.books.length
    }
  },

use
Method 1: not recommended

<template>
{{$store.getters.GET_BOOK_NUM}}
</template>

Method 2: attribute calculation method

<template>
{{GET_BOOK_NUM}}
</template>
computed:{
    GET_BOOK_NUM(){
      return this.$store.getters.GET_BOOK_NUM
    }
}

Method 3: auxiliary function (commonly used in projects)

<template>
{{GET_BOOK_NUM}}
</template>
import {mapGetters} from 'vuex'
computed:{  
      ...mapGetters(['GET_BOOK_NUM'])  
}

mutations

The only way to change the state in Vuex's store is to submit the mutation.
The mutation in Vuex is very similar to events (encapsulation methods, parameters can be passed): each mutation has a string event type and a callback function (handler).
This callback function is where we actually change the state, and it will accept state as the first parameter

  • No transmission parameter

definition

 state: {
	   num:0
	 },
mutations: {
    add(state){
      state.num++;
    }
 },

use
Method 1: traditional usage

<template>
{{num}}
<button @click="add">+</button>
</template>
methods:{
    add(){
      this.$store.commit('add')
    }
}

Method 2: auxiliary function

<template>
	{{num}}
	<button @click="add">+</button>
	</template>
	import {mapMutations} from 'vuex'  //auxiliary function 
	methods:{
	    ...mapMutations(['add'])  //Deconstruction into instance method
	}
  • Transmission parameter

definition

    state: {
	   num:0
	 },
	mutations: {
	    add(state,n){
	      state.num+=n;
	    }
     },

use
Method 1:

   <template>
	{{num}}
	<button @click="add(2)">+2</button>
   </template>
	add(){
      this.$store.commit('add',2)
     },

Method 2:

   <template>
	{{num}}
	<button @click="add(2)">+2</button>
   </template>
   //When passing parameters, you can pass them in a more readable way
	store.commit({type: 'add',num: 2})

In Vuex, mutation is a synchronous transaction

Action

Similar to mutation, you can encapsulate methods, except that

  • The Action submits the mutation instead of directly changing the status
  • An Action can contain any asynchronous Action

definition

  actions: {
    async_add(context,n){
      setTimeout(() => {
        context.commit('add',2) //Here we can use the method in the mutation in the warehouse and it can be asynchronous!
      }, 2000); //Use asynchronous events in Action
    }
  },

use
Method 1: traditional usage

<template>
{{num}}
<button @click="async_add(2)">+2</button>
</template>
methods:{
	async_add(n){
      this.$store.dispatch('async_add',n)
    } //Traditional writing
 }

Method 2: auxiliary function

<template>
{{num}}
<button @click="async_add(2)">+2</button>  //Asynchronous. Add 2 in two seconds
</template>
import {mapActions}  from  'vuex'
methods:{
	...mapActions(['async_add']) //auxiliary function 
 }

module

Due to the use of a single state tree, all the states of the application will be concentrated in a relatively large object. When the application becomes very complex, the store object may become quite bloated.
Vuex allows us to split the store into modules. Each module has its own state, mutation, action, getter, and even nested sub modules.
For the mutation and getter inside the module, the first parameter received is the local state object of the module.
For action s inside the module, the local state is exposed through context.state, and the root node state is context.rootState

In the store folder, create a new module subfolder as the sub module, and in the module module, create home.js as the sub warehouse home

Namespace

By default, the action, mutation and getter inside the module are registered in the global namespace -- this enables multiple modules to respond to the same mutation or action.

Make the sub module a module with namespace by adding named: true.
When a module is registered, all its getter s, action s and mutation s will be automatically named according to the path of module registration.

After the module is divided, the value taking method can be changed appropriately to facilitate our value taking:

Sub warehouse store/module/home.js

export default{
    namespaced:true,//Open namespace
    state(){
        return{
            name:'home'
        }
    }
}

Main warehouse / index.js

import { createStore } from 'vuex'
import home from './modules/home'  //Import sub warehouse into general warehouse
export default createStore({
  state: {
    name:app,
    msg:'is store',
    num:0
  },
 })

Use Home.vue in component

<template>
  {{msg}}
  {{num}}
  {{name}}
</template>
<script>
import {mapState} from 'vuex'
export default{
 computed:{
 	...mapState('home',['name']), //The name in the home warehouse is displayed as home
 	...mapState(['name']);Default to the primary warehouse name Value, is app ;The following will overwrite the above, which is displayed in the page name Value is app
 	...mapState(['msg','num']), //There are msg and num in the main warehouse, which are displayed directly
 	...mapState({
 		 home_name: (state)=>{state.home.name}, //Read the name value in the home warehouse, which is home
 		 name:(state)=>{state.name} //Read the name value in the main warehouse, which is app
 		 //Rename the name in different warehouses to make the name different
  }),
 }

Topics: Javascript Front-end Vue Vue.js