Basic knowledge of vuex

vuex

Shared state (data) management tool

installation

npm i vuex

Use in vue

Configure in main.js

import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
    
    
  state:{
    
    
    // 状态(数据)
    count:0
  }
});
new Vue({
    
    
  router,
  store,
  render: h => h(App),
}).$mount('#app')

After configuration, you can use the vue-devtool tool to view in the browser

F12 to open the console, vue-》vuex

  • Generally, the configuration of vuex is placed in store.js, and then introduced in main.js

Configuration in store.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
    
    
    state:{
    
    
        count:0
    }
})
export default store;

Get the state (data) of vuex in the component

After configuration, Vue.use(Vuex)inject the state follower component into each sub-component

Sub-components can this.$storeaccess the state of vuex

this.$storeAs an object, there are many functions in it

this.$store.stateIs the state of our configuration

this.$store.state.countGet specific status

组件中改变了状态,那么也会影响到使用到这个状态的组件

Use in the view

direct{ { $store.state.count }}

Write a long list in this way, then you can use it as the component's own attribute and use the calculated attribute to achieve it.

<template>
  <div class="home">
    首页
    <button @click="$store.state.count++">点击</button>
    <!-- {
   
   { $store.state.count }} -->
    {
   
   { count }}
  </div>
</template>

<script>
export default {
  computed:{
      count(){
          return this.$store.state.count;
      }
  },
};
</script>

Writing in this way will still cause redundancy, because there may be many states.

Vuex helped us solve this problem.

// 需要引入
import {
    
     mapState } from 'vuex';
export default {
    
    
  computed:{
    
    
    //   count(){
    
    
    //       return this.$store.state.count;
    //   }
    // mapState(['count']) 会返回一个计算函数
    ...mapState(['count'])
  },

After the same name as the data in the component, the priority of data is higher. This is because we need to rename it. You can change the data name in data. If the data name in data participates in too much logic, then you can change the data in mapState. name

mapState({
    
    
  // 重命名的数据变量 后面是一个函数,函数第一个参数是state,函数的返回值就是变量的值
  storeCount:(state) => state.count;
  // 如果不需要对仓库中的状态处理的话,可以简写
  storeCount:'count'; //(state) => state.count;
})

getter

The getter is a calculated attribute of the store. The return value of the getter will be cached according to its dependencies
and will be recalculated only when its dependency value changes.

  • use

Configure in store.js

const store = new Vuex.Store({
    
    
    state:{
    
    
        count:0,
        studentList:[]
    },
    // 是复数 有多个getters,里面是函数,第一个参数是state
    getters:{
    
    
        doubleCount(state){
    
    
            return state.count * 2;
        },
        // 可以返回一个函数
        addCount(state){
    
    
          return function(num){
    
    
            return state.count + num;
          }
        }


    },
})  

Configured and used in the component like count, you can
{ {$store.getters.doubleCount }} in the view

  • mapGetters helper function

Similar to mapState

Introduce mapGetters in the component

import {
    
     mapGetters } from 'vuex';


computed:{
    
    
    //   count(){
    
    
    //       return this.$store.state.count;
    //   }
    ...mapState(['count']),
    ...mapGetters(['addCount','doubleCount'])
  },

mutation

English means variation, change

In strict mode of vuex

To enable strict mode, only need to pass strict: true when creating the store

const store = new Vuex.Store({
    
    
  //...
  strict:true
})

在严格模式下,无论何时发生了状态变更且不是mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

更改vuex的store中的状态的唯一方法是提交mutation

One-way data flow in vuex

State -> view change -> mutation -> state

Development environment and release environment

Do not turn on strict mode in the release environment. Strict mode will deeply monitor the state tree to detect unqualified state changes. Make sure to turn off strict mode in the release environment to avoid performance loss.

const store = new Vuex.Store({
    
    
  //...
  strict: process.env.NODE_ENV !== 'production'
})

mutation use

In the store configuration

  mutations:{
    
    
        countIncrement(state){
    
    
            // 变更状态
            state.count++;
        }
    }

Submit in the component

methods:{
    
    
      handleClick(){
    
    
          this.$store.commit('countIncrement');
      }
  }
  • mapMutation
  methods:{
    
    
      ...mapMutations('countIncrement'),
      handleClick(){
    
    
        //   this.$store.commit('countIncrement');
        this.countIncrement();
      }
  }
  • Why not use mapMutation in computed, it returns a function.

  • The mutation changes the state according to the parameters passed at the time of submission

 mutations:{
    
    
        countIncrement(state,num){
    
    
            // 变更状态
            state.count += num;
        }
    }
methods:{
    
    
    //   ...mapMutations('countIncrement',10),
      handleClick(){
    
    
        // 第二个就是要传递的参数 一般写成一个对象
          this.$store.commit('countIncrement',
          {
    
     
                num: Math.floor(Math.random()* 100;
          }
          );
          // this.$store.commit('countIncrement',10);
        // this.countIncrement();
      }
  }

If it is written as an object, then the mutations must be deconstructed

mutations:{
    
    
        countIncrement(state,{
    
    num}){
    
    
            // 变更状态
            state.count += num;
        }
    }

The second parameter in commit is professionally called payload.

The parameters in commit can be passed directly to an object

this.$store.commit({
    
    
            //   mutaion的函数名
              type:'countIncrement',
            //   数据
              num:10
          });

store.js

mutations: {
    
    
        countIncrement(state, payload) {
    
    
            // 变更状态
            state.count += payload.num;
        }
    }

mutation configuration file

You can put the name of the mutation in a separate file, with the name in uppercase

mutation-types.js中

export const COUNT_INCREMENT = 'COUNT_INCREMENT';
import {
    
    
    COUNT_INCREMENT
} from './mutation-types.js';
mutations: {
    
    
        // countIncrement(state, payload) {
    
    
        //     // 变更状态
        //     state.count += payload.num;
        // }
        [COUNT_INCREMENT](state,payload){
    
    
            state.count += payload.num;
        }
    }

Component

this.$store.commit({
    
    
            //   mutaion的函数名
              type:'COUNT_INCREMENT',
            //   数据
              num:10
          });

Mutations need to comply with Vue's response rules

When you need to add new properties to the object, you should use it, otherwise the view will not refresh

  1. Vue.set (obj, 'newProp', 123);

  2. Replace old objects with new ones, for example

state.obj = {
    
    ...state.obj,newProp:123}
 [OBJ_B](state,payload){
    
    
            Vue.set(state.obj,'b',2)
            // state.obj = {...state.obj,b:2};
        }

Form processing

When using v-model on the state of vuex, since the value of state will be directly changed, vue will throw an error.

If you want to use the two-way data function, you need to simulate one yourself, as follows:

mutation-types.js file

export const CHANGE_MSG = 'CHANGE_MSG';
import {
    
    CHANGE_MSG} from 'mutation-types.js';
const store = new Vuex.Store({
    
    
  state:{
    
    
    msg:''
  },
  mutations:{
    
    
    [CHANGE_MSG](state,{
    
    value}){
    
    
      state.msg = value;
    }
  }
})
<template>
  <div>
        <input :value="msg" @input="handleInput" />{
   
   { msg }}
  </div>
</template>

<script>
import {mapState} from 'vuex';
import {CHANGE_MSG} from 'mutation-types.js';
  export default {
      computed:{
        ...mapState(['msg'])
      },
      methods:{
        handleInput(e){
          this.$store.commit(CHANGE_MSG,{value: e.target.value});
        }
      }
  }
</script>

The above implementation method is a bit troublesome

It can also be achieved with the help of the get and set methods in the calculated properties

<template>
  <div>
        <input v-model='msg'/>{
   
   { msg }}
  </div>
</template>

<script>
import {mapState} from 'vuex';
import {CHANGE_MSG} from 'mutation-types.js';
  export default {
      computed:{
        // ...mapState(['msg']);
         msg:{
        get(){
            return this.$store.state.msg;
        },
        set(value){
            this.$store.commit(CHANGE_MSG,{value})
            }
        }
      }, 
  }
</script>
export const CHANGE_MSG = 'CHANGE_MSG';
import {
    
    CHANGE_MSG} from 'mutation-types.js';
const store = new Vuex.Store({
    
    
  state:{
    
    
    msg:''
  },
  mutations:{
    
    
    [CHANGE_MSG](state,{
    
    value}){
    
    
      state.msg = value;
    }
  }
})

The function in the mutation cannot be asynchronous

  • Asynchrony will cause debugging problems and cannot be traced. Vue will also report errors that cannot be changed outside the mutation. Asynchronous functions will be executed in the asynchronous queue.

  • action will solve this problem

Action

Action and mutation are similar, but there are two differences:

  1. Action cannot directly change the state, but by submitting a mutation to change the state

  2. Action can contain any asynchronous operation, and mutation cannot

action and function accepts a store instances of the same methods and properties of the context object, can be invoked directly context.commitsubmit a mutation, or by context.gettersand context.stateacquired state and getters

const store = new Vuex.Store({
    
    
  state:{
    
    
    count:0
  },
  mutations:{
    
    
    increment(state){
    
    
      state.count++;
    }
  },
  actions:{
    
    
    increment(context){
    
    
      context.commit('increment');
    }
  }
})

How to use the action in the component, which needs to distribute the action

Distribute action

this.$store.dispatch('increment')

Off and map

  • mapState calculated properties
  • mapGetters calculated attributes
  • mapMutations returns a function methods
  • mapActions returns a function methods

Asynchronous operations

mutation submitted by action

actions: {
    
    
        countIncrement(context) {
    
    
            setTimeout(() => {
    
    
                context.commit('increment');
            }, 1000)
        }
    }
  • Then how to know the end time of the asynchronous action, you can return a promise in the actions function.
actions: {
    
    
        countIncrement(context) {
    
    
            return new Promise((resolve,reject) => {
    
    
                setTimeout(() => {
    
    
                    context.commit('increment');
                    resolve(12);
                }, 1000)
            })
           
        }
    }

When distributing, then a pop-up box will pop up

this.$store.dispatch('countIncrement').then(res=>{
    
    
          alert('actions结束'+res);
      });

Module

Previously, a single state number was used, and all the states of the application will be concentrated into a relatively large object.
So modules are here to solve this problem, vuex allows us to split modules (module). Each module has its own state, getter, mutation, and action.

const store = new Vuex.Store({
    
    
  modules:{
    
    
    module1,
    module2
  }
})

注意

  1. Only add the above module name when obtaining state, other normal use
  2. Get state:this.$store.modulesName.xxx;
  3. Get the getter:this.$store.getters.xxx;
  4. Submit mutation:this.$store.commit(xxx);
  5. Distribute actin:this.$store.dispatch(xxx);
  6. Corresponding can be obtained through mapstate, mapGetters, mapMutation, and mapAction, but mapState cannot be obtained. To achieve this, a namespace is required.

Namespaces

It can be namespace:truemade into a module with a namespace by adding .

Get state: this.$store.state.modulesName.xxx;
get getter: this.$store.getters['modulesName/xxx'];
submit mutation: this.$store.commit('modulesName/xxx');
distribute actin:this.$store.dispatch('modules/xxx');

Local state of the module

  • For the mutation and getter inside the module, the first parameter accepted is the local object of the module.

  • For actions inside the module, the local state is exposed through context.state, and the root node is context.rootState

  • For the getter inside the module, the root node state will be exposed as the third parameter

Guess you like

Origin blog.csdn.net/tscn1/article/details/111087957