Detailed explanation of how vue3 uses provide to realize state management

  • 2021-11-29 05:54:04
  • OfStack

Preface to the table of contents How to realize the function of Vuex through provide/inject Register this plug-in in the application
Entry file of plug-in
Create store and mount the corresponding data on the root component
Implementing mapState, mapMutations, and mapActions methods
Component to use in the
Summarize

Preface

In the Vue ecosystem, Vuex, the official state management library, has brought us very convenient functions in the application development of Vue. However, the size of Vuex 20K + also brings some costs. For small-scale applications, Vuex is only introduced to store a small amount of data such as user information, which is a bit unworthwhile.

Vue 2.2. x provides provide/inject API at a later stage to help us communicate across hierarchical components.

Vue3.x also puts provide on the application of API, which makes it more convenient for us to realize a basic state management on this basis.

How to realize the function of Vuex through provide/inject

First of all, we want a general logic, make it a plug-in, and register it in the application instance through use method.

In install method, the data is mounted on the root component by app. provide method, and the data should be a responsive data. In order to ensure data security, the change of data should be limited, and the design of one-way data flow should be followed, and users should not modify it directly. Therefore, when exposing data, readonly (read-only) processing should be carried out on the data.

Implement useStore functionality similar to Vuex, allowing users to access data through this method.

Implement mapState, mapMutations, and mapActions methods similar to Vuex to simplify operation.

The usage is directly similar to that of Vuex 1.

Register this plug-in in the application


// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

import store from './store'

const app = createApp(App)

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

Entry file of plug-in

In the entry file, export all methods directly.


// sky-vuex/index.ts
export * from './main/index'

Create store and mount the corresponding data on the root component

store itself is an object containing state attributes and commit, dispatch and other methods. The main function of store is that all components can get store objects, get data in state, and call related methods to modify state.


// sky-vuex/main/index.ts
import {inject, reactive, readonly} from 'vue'

const mainStoreSky = Symbol('main store key')

interface storeOptions {
  state?: any
  actions?: any
  mutations?: any
}

export const createStore = (options: storeOptions = {}) => { //  Create  store  Object 
  const initOptions = {
    state: {},
    actions: {},
    mutations: {},
  }

  const mergeOptions: storeOptions = Object.assign(initOptions, options)

  const state = reactive(mergeOptions.state)

  const store = {
    state: readonly(state),
    dispatch(eventName: string, ...args: any[]) {
      mergeOptions.actions[eventName](store, ...args)
    },
    commit(eventName: string, ...args: any[]) {
      ...
    },
  }

  return {
    install(app: any) {
      app.provide(mainStoreSky, store)
    },
  }
}

export const useStore = (): any => { //  Other components use this method to get the  store  Object 
  return inject(mainStoreSky)
}

Implementation of mapState, mapMutations, and mapActions methods


export const mapState = () => {
  const store = useStore()
  return store.state
}

export const mapActions = (eventName: string) => {
  const store = useStore()
  return (...args: any[]) => store.dispatch(eventName, ...args)
}

export const mapMutations = (eventName: string) => {
  const store = useStore()
  return (...args: any[]) => store.commit(eventName, ...args)
}

Component to use in the


// store/index.ts
import { createStore } from '../sky-vuex/index'

export default createStore({
  state: {
    age: 18
  },
  mutations: {
    setAge(state: any, data: number) {
      state.age = data
    }
  },
})


// Home.vue
<template>
  <div class="home">
    <button @click="handleAge(23)"> Modify data </button>
    <h1>{{ state.age }}</h1>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useStore, mapActions, mapMutations } from '@/sky-vuex/index'

export default defineComponent({
  name: 'Home',
  setup() {
    const store = useStore()

    const handleAge = mapMutations('setAge')
    // const handleAge = mapActions('setAge')

    // const handleAge = () => {
    //   store.dispatch('setAge', 5)
    // }

    return {
      state: store.state,
      handleAge,
    }
  },
})
</script>

Summarize

So far has achieved the basic Vuex function, you can do it yourself under the practice of 1, optimization, any questions are welcome to put forward


Related articles: