Understand vuex4 X basic usage and comparison vue3 Difference of X

brief introduction

Vuex is Vue JS application state management mode + library. It acts as a centralized storage for all components in the application, and its rules ensure that the state can only be changed in a predictable way.

In short, it provides a library of state management, and the change of state is predictable.

Status: I personally understand that any variable in your component can be a status. As long as you want, you can write it into the state, but I'm sure you won't.

install

  1. For existing projects, you can use vue add vuex to add vuex.
  2. When creating a project, you can select Manually select features to customize the configuration.
  3. npm install vuex@next --To save, you need to create a store file manually. The first two are recommended.

After installation, a store folder will be created under the src file of the project, with an index file inside

// index.js

import { createStore } from 'vuex'

export default createStore({
	state: {},
	getters: {},
	mutations: {},
	actions: {},
	modules: {}
})

vuex4. In order to keep consistent with vue3's creation method, it is recommended to use createStore to create X

Core concept

state

Store data

Add a variable count to state. At this time, count will be accessible in any component under the project. The data in state is called state. Storing data in state is the same as storing data in data memory.

state(){
    count: 0
}

Access count in component

  • $store. In template state. count
  • This. In object$ store. state. count

Since Vuex stores are reactive, the easiest way to retrieve status from them is to simply return some store status from calculated properties:

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

At this point, you can access the data count in the store by calculating the attribute count. Whenever the count in the store is modified, it will cause the calculation property to be recalculated and trigger the associated DOM update.

If too many states need to be introduced, the code will obviously become repetitive and lengthy when Binding calculation attributes to each state. To solve this problem, import the mapState method.

mapState can help us generate the calculated state function.

mapState

You need to import mapState module from vuex

import { mapState } from 'vuex'

There are two ways to use mapState

// Incoming object form
computed: mapState({
  // First kind
  count: state => state.count,
  // The second: passing the string 'count' is equivalent to state = > state count
  countAlias: 'count',
  // The third method: define localcount in data in combination with the current component status
  countPlusLocalState(state){
    return state.count + this.localcount;
  }
})

mapState when the name of the mapped calculated attribute is the same as the name of the state subtree, we can also pass a string array.

computed: mapState([ 'count' ])

When visiting

this.count

The computed of the store is combined with the computed of the component

If the calculated attribute of the current component is used together with the calculated attribute of the store, you need to use the object extension operator.

mapState returns an object

computed: {
  localCountDecorate(){
    return `Local component status ${this.localcount}`
  },
  // You can pass an array or an object
  ...mapState([ 'count' ])
}

The component calculation properties written in mapState are also valid, but the parameters accepted are different, so they need to be separated

Components can still have local state

Using Vuex does not mean that you should put all States into Vuex. While adding more states to Vuex can make your state transitions more explicit and debuggable, sometimes it can also make your code more verbose and indirect. If a state strictly belongs to a single component, it is OK to keep it local.

getters

getters can be called decorators. They can do a layer of processing (decorating / filtering) on the data in the state and return it to the component.

First, create a status (product list) in state

articleList: [
      {id: '001', articleName: 'xinjiang cotton', description: 'Xinjiang is rich in high-quality long staple cotton', stock: 1000000, price: 100},
      {id: '002', articleName: 'shoe', description: 'LiNing Wade's way 4', stock: 10, price: 100},
      {id: '003', articleName: 'Graphics card', description: '3080 Series graphics card', stock: 0, price: 100},
      {id: '004', articleName: 'vaccine', description: 'New Coronavirus vaccine', stock: 100000000, price: 100},
      {id: '005', articleName: 'xiaomi 11', description: 'xioami 11th generation mobile phone', stock: 100000, price: 100},
      {id: '006', articleName: 'Kirin Chip', description: 'Huawei Kirin chip', stock: 0, price: 100}
    ]

Filter them in getters

getters: {
	Instock(state, getters){ // state as the first parameter, getters accesses other getters
		console.log(getters);
		return state.articleList.filter(item => item.stock != 0);
	}
}

getters receives two parameters

  • State: access the state in the current store
  • Getters: access other getters in the current store

Now filter the status articleList in the state once, and remove all the items with stock 0.

Access in component

The access method is the same as state

computed: {
	Instock(){ // You may not use the same name
      return this.$store.getters.Instock;
    }
}

Similarly, mapGetters can be used to map to computed to reduce the amount of code.

mapGetters

The rule is the same as mapState

computed: {
	...mapState(['Instock'])
}

When visiting

this.Instock()

Get specified data

getters can return a function to receive the input of a parameter for finding data.

// getters
searchArticle: (state) => (id) => { // The return function passes in the id and uses the id to find the data
	return state.articleList.filter(item => item.id == id);
}

In component

...mapGetters([ 'Instock', 'searchArticle' ])

At this time, you can pass parameters to return the specified data

this.searchArticle('001'); // Specify the data whose return id is 001

getters only has the ability to decorate and return the state in the state, and cannot directly change the state. Changes are required to change state.

mutations

State changes in state can only be made in changes. And asynchronous operations cannot exist in mutations

mutations: {
	addCount(state, payload){
		// Parameter accumulation executed in the receiving component
		state.count += payload.count;
	}
}

Two parameters are acceptable

  • State: access the state of the current store
  • payload: parameter passed. In most cases, it should be an object to pass more state

Declared in methods in component. Changes submit changes through commit.

// template
<button @click="addCount">increase</button>

// js
methods: {
	addCount(){
		this.$store.commit('addCount', {count: 1}); // Parameters passed by {count: 1}
	}
}

Simplification: mapMutations

import { mapMutations } from 'vuex';
methods: {
	// Pass array
	...mapMutations(['addCount']) // this.addCount() execution
	// Transfer object (assign new value)
	...mapMutations({ localtotal: 'addCount' }) // this.localtotal() execution
}

In some cases, it is inevitable to make requests or other asynchronous operations when changing data, and asynchronous operations are not allowed in mutations. actions will be used

actions

Actions are similar to mutations, except that:

  • The action does not change the state, but performs the change.
  • Actions can contain any asynchronous operation.

Actions does not have the right to change the state, but can commit changes, so actions only performs changes.

actions: {
	asynCount(context, products){
		setTimeout(() => {
			context.commit('addCount', products);
		}, 1000);
	}
}

Receive two parameters

  • Context: store context object. Deconstruction can be used, including commit, dispatch, getters, rootGetters, state and rootState
  • products: parameters passed

Call in component. actions are triggered by dispatch

// template
<button @click="asynAddCount">Add one after one second</button>

// js
methods: {
	asynAddCount(){
		this.$store.dispatch('asynCount', { count: 3 });
	}
}

Simplify: mapActions

import { mapActions } from 'vuex';
methods: {
	// Pass array
	...mapActions(['asynCount']) // this.asynCount() execution

	// Transfer object
	...mapActions({ localAsyncTotal: 'asynCount' }) // this.localAsyncTotal() execution
}

mudeles

As our apps grow in size, the store may become bloated. To solve this problem, Vuex allows us to divide the store into modules. Each module can contain its own state, variation, action, getter, or even nested modules - the whole process is fractal

In the case of larger and larger projects, it is particularly necessary to divide modules.
The file is deconstructed as follows

store
└─ index.js
└─ moduleA.js
└─ moduleAInside.js
└─ moduleB.js

Code in file

// index.js
import { createStore } from 'vuex'
import moduleA from './moduleA'
import moduleB from './moduleB'

export default createStore({
  state: {
    count: 0,
  },
  getters: {
  },
  mutations: {
    addCount(state, payload){
      state.count += payload.count;
    }
  },
  actions: {
    asynCount(context, products){
      setTimeout(() => {
        context.commit('addCount', products);
      }, 1000);
    }
  },
  modules: {
    moduleA,
    moduleB
  }
})
// moduleA.js
import moduleAInside from './moduleAInside'
const moduleA = {
    state: () => ({
        moduleAstate: 'unknown'
    }),
    getters: { ... },
    mutations: { ... },
    actions: { ... },
    modules: {
    	moduleAInside 
	}
}

export default moduleA;
// moduleAinside.js
const moduleAInside = {
    state: () => ({
        moduleAInsideState: 'unknown'
    }),
    getters: { ... },
    mutations: { ... },
    actions: { ... }
}

export default moduleAInside;
// moduleB.js
const moduleB = {
    state: () => ({
        moduleBstate: 'unknown'
    }),
    getters: { ... },
    mutations: { ... },
    actions: { ... }
}

export default moduleB;

The usage inside the module is the same as that outside. Similarly, modules can be nested inside the module.

About accessing other modules or root modules within a module.

  • *** * the third module root, gets root and the fourth module root can be accessed
  • **Actions: * * the context of actions contains rootState and rootGetters, which can be used to access other modules and root modules.

senior

vue3 introduces a composite api in which you can use the useStore function to create a reference to vuex, which is equivalent to this$ store

import { useStore } from 'vuex'

export default {
    setup(){
        const store = useStore();
    }
}

Access state and getters

Since I access the status in the comAPI module, I need to access the module before accessing the specific status when accessing the state, and getters is not required.

const comState = computed(() => store.state.comAPI.comAPIState);
const comGetters = computed(() => store.getters.comAPIGetters);

Access changes and actions

Accessing changes and actions does not need to consider the scope of the module.

const changeState = () => { store.commit('changeState') }
const asynChangeState = () => { store.dispatch('asynChangeState') }

Compare vuex4 & vuex3

Creation method

vuex4 and vue3 are created in the same way

import { createStore } from 'vuex'

export const store = createStore({
  ...
})

Install to vue

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

const app = createApp(App)
app.use(store)
app.mount('#app')

New combined API useStore

import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
  }
}

Keywords: Vue

Added by traxy on Sat, 19 Feb 2022 06:11:30 +0200