A simple and detailed explanation of VueX, you will be able to use it after reading it

1. What is VueX

Vuex is a state management pattern + library         developed specifically for Vue.js applications . It uses 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.

2. Why use VueX

        A simple illustration of the "one-way data flow" concept:

The simplicity of one-way 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 require changing the same state.

        Regarding question 1, the method of passing parameters will be very cumbersome for multi-layer nested components, and it is powerless for state transfer between sibling components. For question two, we often use parent-child components to directly reference or use events to change and synchronize multiple copies of the state. These patterns are very fragile and often lead to unmaintainable code.

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

        By defining and isolating the various concepts in state management and maintaining the independence between views and state by enforcing rules, our code will become more structured and maintainable.

VueX was born from this:

 3. Five major modules of VueX

(1) State: single state tree

        Vuex uses a single state tree - yes, a single object that contains all application-level state. At this point it exists as a "single source of data ( SSOT )". This also means that each application will only contain one store instance. A single state tree allows us to directly locate any specific piece of state and easily obtain a snapshot of the entire current application state during debugging.

        To put it simply, all states in the project are placed in State.

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    // 全局个人数据
    userInfo:{},
    isLogin:true,
    loading:false,
    tabActive:0
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

        How to get it when using it on other pages

1. Get the value directly from the store instance

         In main.js, register the store under the root instance

import store from './store'
    (1) In other page js, you can use this.$stroe.state. attribute to directly obtain the value.
export default {
  computed: {
    testNum() {
      return this.$store.state.testNum;
    }
  }
};

        (2) Write the $stroe.state. attribute in the html of other pages.

<div class="box" v-id="$store.state.isLogin">
    <MySelfHeader></MySelfHeader>
    <MySelfBody></MySelfBody>
</div>

2.mapState auxiliary function

        When a component needs to obtain multiple states, declaring these states as computed properties will be somewhat repetitive and redundant. To solve this problem, we can use  mapState helper functions to help us generate computed properties.

    First introduce import {mapState} from "vuex";
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

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

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

(2) Getter

        Sometimes we need to derive some state from the state in the store, such as filtering and counting the list:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

         Vuex allows us to define "getters" in the store (which can be thought of as computed properties of the store).

         Getter accepts state as its first parameter:

const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos (state) {
      return state.todos.filter(todo => todo.done)
    }
  }
})

How to get it on other pages:

        In Js: this.$store.getters.method/property

        In html: $store.getters.method/property

(3) Mutation

        The only way to change the state in the Vuex store is to submit a mutation . Mutations in Vuex are very similar to events: each mutation has a string event type (type) and a callback function (handler) . This callback function is where we actually make the state changes, and it accepts state as the first parameter:

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

         You cannot call a mutation handler directly. This option is more like an event registration: "When a  increment mutation of type is triggered, call this function." To wake up a mutation handler, you need to call the  store.commit  method with the corresponding type:

store.commit('increment')

Submit payload

        You can  store.commit pass in additional parameters, the payload of the mutation :

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment', {
  amount: 10
})

Note: Mutation must be a synchronous function, and asynchronous operations cannot be performed in Mutation.

***Submit Mutation in component***

        You can use commit mutations in components  this.$store.commit('xxx') , or use  mapMutations helper functions to map methods in components to  store.commit calls (need to be injected at the root node  store).

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

Important: Methods in Mutation must be called through commit

(4) Action

        In some cases, we want to perform some asynchronous operations in vuex, such as network requests, which must be asynchronous, so we need to use actions at this time.

Action is similar to mutation, except that:

  • Action submits a mutation rather than directly changing the state.
  • Action can contain any asynchronous operation.
const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

The Action function accepts a context object         with the same methods and properties as the store instance , so you can call  context.commit Submit a mutation, or   obtain state and getters through context.state and  .context.getters

DistributeAction

        Action  store.dispatch is triggered via methods:

store.dispatch('increment')

        At first glance, it seems unnecessary. Wouldn't it be more convenient for us to distribute mutations directly? In fact, this is not the case. Remember  the restriction that mutations must be executed synchronously ? Action is not restricted! We can perform asynchronous operations inside the action :

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

        Actions supports the same payload method and object method for distribution:

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

// 以对象形式分发
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

****Distributing Actions in Components***

this.$store.dispatch('xxx') You use dispatch actions          in the component  , or use mapActions auxiliary functions to map the component's methods to  store.dispatch calls (you need to inject them in the root node first  store):

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

(5) 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 an application becomes very complex, store objects have the potential to become quite bloated.

        In order to solve the above problems, Vuex allows us to split the store into modules . Each module has its own state, mutation, action, getter, and even nested submodules - divided in the same way from top to bottom:

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

4. VueX source code

let Vue;
//定义一个Store类
class Store {
    constructor () {
        this._vm = new Vue({
            data: {
                $$state: this.state
            }
        })
    }

    commit (type, payload, _options) {
        const entry = this._mutations[type];
        entry.forEach(function commitIterator (handler) {
            handler(payload);
        });
    }

    dispatch (type, payload) {
        const entry = this._actions[type];
        return entry.length > 1
        ? Promise.all(entry.map(handler => handler(payload)))
        : entry[0](payload);
    }
}
//保证 vm 中都可以访问 store 对象
function vuexInit () {
    const options = this.$options;
    if (options.store) {
        this.$store = options.store;
    } else {
        this.$store = options.parent.$store;
    }
}
//Vue.js 提供了一个 Vue.use 的方法来安装插件,内部会调用插件提供的 install 方法。所以我们的插件需要提供一个 install 方法来安装。
export default install (_Vue) {
    
    Vue.mixin({ beforeCreate: vuexInit });
    Vue = _Vue;
}

        For more details, please jump to the official website——

Vuex is this? | Vuex (vuejs.org) icon-default.png?t=M85Bhttps://vuex.vuejs.org/zh/

Guess you like

Origin blog.csdn.net/gkx19898993699/article/details/128166015