current position:Home>Super detailed! Vuex handle tutorial

Super detailed! Vuex handle tutorial

2021-08-26 21:49:42 Peng Duoduo

1, Preface

I've been reviewing vue Family bucket , It feels more profound to see it again , So make a special record ( this paper vuex Version is v3.x).

2,Vuex What is it?

Vuex It's for Vue.js State management mode of development . It uses centralized storage , Manage the state of all components , And the corresponding rules ensure that the state changes in a predictable way ( My understanding is that global variables ).

3,5 Large attribute description

state

object type , Similar to the example data attribute , Storing data

getters

object type , Calculation properties similar to instances computed

mutations

object type , Similar to the example methods, But you can't handle asynchronous methods

actions

object type , Similar to the example methods, Can handle asynchronous methods

modules

object type , When state When there is a lot of content , Split into small modules through this attribute , Each module has its own state、mutation、action、getter

4,state

Stored in state Data in and Vue In the instance data Follow the same rules , It must be a pure object .

4.1 Direct access

this.$store.state.xxx

4.1 Use mapState mapping

<template>
    <div id="communication">
        <p> Count :{{ getCount }}</p>
        <p> School :{{ getSchool(' I am a parameter ') }}</p>
    </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
    name: 'Vuex',
    data() {
        return {
            date: 1998
        }
    },
    computed: {
        ...mapState({
            // mapState By default the state When the first parameter comes in 
            getCount: state => state.count,
            getSchool(state) {
                return (val) => {
                    return state.school + val + this.date
                }
            }
        })
    },
    mounted() {
        //  Direct value 
        console.log(this.$store.state.count)
    }
}
</script>

5,getters

getter The return value of is cached according to its dependency , And only when its dependency value changes will it be recalculated , And accept by default state As its first parameter , You can also accept other getter As the second parameter ( Here's an example )

5.1 First in vuex In the definition of getters

export default new Vuex.Store({
    state: {
        count: 0,
        school: ' Tsinghua University '
    },
    getters: {
        //  Return to the processed state value 
        getValue(state) {
            return state.count + '!'
        },
        //  Returns the call itself getters After processing the state value 
        getGetters(state, getters) {
            return state.school + getters.getValue
        },
        //  Accept the value after external parameter transfer ( When accessed through methods , Every time I make a call , Results are not cached )
        getParam(state) {
            return (param) => {
                return state.school + param
            }
        }
    },
    mutations: {},
    actions: {},
    modules: {}
})

5.2 Get value directly

//  Value 
console.log(this.$store.getters.getGetters)
//  Pass parameter value 
console.log(this.$store.getters.getParam('param'))

5.3 Use mapGetters mapping

<template>
    <div id="communication">
        <p> Count :{{ getGetters }}</p>
        <p> School :{{ getParam(date) }}</p>
    </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
    name: 'Vuex',
    data() {
        return {
            date: 1998
        }
    },
    computed: {
        ...mapGetters([
            'getGetters',
            'getParam'
        ])
    },
    mounted() {
        //  Direct value 
        console.log(this.$store.getters.getGetters)
        console.log(this.getParam(this.date))
    }
}
</script>

6,Mutation

By calling this.$store.commit('xxx'), call mutation The method in , change store The value in

6.1, First in mutations Registered events in

export default new Vuex.Store({
    state: {
        count: 0,
        school: ' Tsinghua University '
    },
    getters: {},
    mutations: {
        //  Default state As the first parameter 
        handleAdd(state) {
            state.count++
        },
        //  Accept the transmission of reference 
        handleChange(state, value) {
            state.school = value
        }
    },
    actions: {},
    modules: {}
})

6.2, Invoke method in component commit Modified value

<template>
    <div id="communication">
        <p> Count :{{ count }}</p>
        <el-button @click="handleStoreAdd"> increase </el-button>
        <el-button @click="handleStoreChange"> The ginseng </el-button>
    </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
    name: 'Vuex',
    data() {
        return {
            school: ' Wuhan University '
        }
    },
    computed: {
        ...mapState([
            'count'
        ])
    },
    methods: {
        //  Call modify 
        handleStoreAdd() {
            this.$store.commit('handleAdd')
        },
        //  Pass parameter modification 
        handleStoreChange() {
            this.$store.commit('handleChange', this.school)
        }
    }
}
</script>

6.3, Use constants to define method names

New file mutation-types.js, Constants that define method names , And export

export const ADD_COUNT = 'ADD_COUNT'
export const CHANGE = 'CHANGE'

stay store in

import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0,
        school: ' Tsinghua University '
    },
    getters: {},
    mutations: {
        //  Default state As the first parameter 
        [MT.ADD_COUNT](state) {
            state.count++
        },
        //  Accept the transmission of reference 
        [MT.CHANGE](state, value) {
            state.school = value
        }
    },
    actions: {},
    modules: {}
})

In components

<template>
    <div id="communication">
        <p> Count :{{ count }}</p>
        <el-button @click="handleStoreAdd"> increase </el-button>
        <el-button @click="handleStoreChange"> The ginseng </el-button>
    </div>
</template>

<script>
import { mapState } from 'vuex'
import * as MT from '../../store/mutation-types'
export default {
    name: 'Vuex',
    data() {
        return {
            school: ' Wuhan University '
        }
    },
    computed: {
        ...mapState([
            'count'
        ])
    },
    methods: {
        //  Call modify 
        handleStoreAdd() {
            this.$store.commit(MT.ADD_COUNT)
        },
        //  Pass parameter modification 
        handleStoreChange() {
            this.$store.commit(MT.CHANGE, this.school)
        }
    }
}
</script>

6.4, Use mapMutations mapping

<template>
    <div id="communication">
        <p> Count :{{ count }}</p>
        <p> Count :{{ school }}</p>
        <el-button @click="handleStoreAdd"> increase </el-button>
        <el-button @click="handleStoreChange(schools)"> The ginseng </el-button>
    </div>
</template>

<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '../../store/mutation-types'

export default {
    name: 'Vuex',
    data() {
        return {
            schools: ' Wuhan University '
        }
    },
    computed: {
        ...mapState([
            'count',
            'school'
        ])
    },
    methods: {
        ...mapMutations({
            handleStoreAdd: MT.ADD_COUNT,
            handleStoreChange: MT.CHANGE
        })
    }
}
</script>

7,Action

Be careful ,Action Is submitted mutation, Instead of changing the state directly , And can contain any asynchronous operation

7.1, stay store In the definition of

import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0,
        school: ' Tsinghua University '
    },
    getters: {},
    mutations: {
        //  Default state As the first parameter 
        [MT.ADD_COUNT](state) {
            state.count++
        },
        //  Accept the transmission of reference 
        [MT.CHANGE](state, value) {
            state.school = value
        }
    },
    actions: {
        add(context) {
            context.commit(MT.ADD_COUNT)
        }
    },
    modules: {}
})

7.2, Use in components

<template>
    <div id="communication">
        <p> Count :{{ count }}</p>
        <el-button @click="actionAdd"> increase </el-button>
    </div>
</template>

<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '../../store/mutation-types'

export default {
    name: 'Vuex',
    data() {
        return {
            schools: ' Wuhan University '
        }
    },
    computed: {
        ...mapState([
            'count',
            'school'
        ])
    },
    methods: {
        ...mapMutations({
            handleStoreAdd: MT.ADD_COUNT,
            handleStoreChange: MT.CHANGE
        }),
        //  call action Methods , Need to use $store.dispatch
        actionAdd() {
            this.$store.dispatch('add')
        }
    }
}
</script>

7.3, Use mapActions mapping

import { mapActions } from 'vuex'

methods: {
    ...mapActions([
        'moduleFn'
    ])
}

perhaps

import { mapActions } from 'vuex'

methods: {
    ...mapActions([
        fn: 'moduleFn'
    ])
}

7.4, Simplify writing

Action Accept a relationship with store The instance has the same methods and properties context Parameter object , So you can call context.commit To submit a mutation, Or by context.state and context.getters To get state and getters, utilize ES6 Deconstruction of , It can be simplified .

actions: {
  add({ commit, state }) {
    commit(MT.CHANGE, state.school)
  }
}

7.5, Perform asynchronous operations

stay vuex in

import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0
    },
    getters: {},
    mutations: {
        //  Default state As the first parameter 
        [MT.ADD_COUNT](state) {
            state.count++
        }
    },
    actions: {
        add({ commit }) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    commit(MT.ADD_COUNT)
                    resolve()
                }, 1000)
            })
        }
    },
    modules: {}
})

Use in components async / await perhaps then / catch Deal with asynchronous

<template>
    <div id="communication">
        <p> Count :{{ count }}</p>
        <el-button @click="actionAdd"> increase </el-button>
    </div>
</template>

<script>
import { mapState, mapMutations } from 'vuex'
import * as MT from '../../store/mutation-types'

export default {
    name: 'Vuex',
    data() {
        return {
            schools: ' Wuhan University '
        }
    },
    computed: {
        ...mapState([
            'count',
            'school'
        ])
    },
    methods: {
        ...mapMutations({
            handleStoreAdd: MT.ADD_COUNT,
            handleStoreChange: MT.CHANGE
        }),
        //  call action Methods , Need to use $store.dispatch
        async actionAdd() {
            await this.$store.dispatch('add')
            console.log(1998)
        }
    }
}
</script>

8,Modules

When the application becomes very complex ,store Objects can become quite bloated . At this time, you can store Split into modules , Each module has its own statemutationactiongetter、 Even nested submodules , Divide from top to bottom in the same way .

8.1, preparation

stay store New under the directory Modules Folder , stay Modules New in folder modulesA.js,modulesB.js, Here's the picture

 Catalog

stay modulesA.js Write the of local modules in statemutationactiongetter, And export

const moduleA = {
    state: () => ({
        a: ' I am a moduleA'
    }),
    getters: {},
    mutations: {},
    actions: {}
}

export default moduleA

And then in store Of index.js Introduction in , And throw it in modules In the object

import Vue from 'vue'
import Vuex from 'vuex'
import * as MT from './mutation-types'
import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0
    },
    getters: {},
    mutations: {},
    actions: {},
    modules: {
        moduleA,
        moduleB
    }
})

8.2, Use modules Of modules injected in state

Use... Directly in components

this.$store.state.moduleA.xxx

Use in components mapState mapping

<span>{{ moduleA.xxx }}</span>

import { mapState } from 'vuex'

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

8.3, Use modules Of the injection module getters

Use... Directly in components

this.$store.getters.getModuleA

Use in components mapState mapping

<p>{{ getModuleA }}</p>

import { mapGetters } from 'vuex'

computed: {
    ...mapGetters([
        'getModuleA'
    ])
}

Internal to the module getter, Accepted parameters state and getters Is the local state object of the module , The state of the root node is the third parameter rootState Exposed

const moduleA = {
    getters: {
        getModuleA(state, getters, rootState) {
            return state.xxx + '---' + rootState.xxx
        }
    }
}

If you need to take parameters

const moduleA = {
    getters: {
        getModuleA(state, getters, rootState) {
            return (value) => {
                return state.a + '---' + value
            }
        }
    }
}

8.4, Use modules Of the injection module mutations

Use... Directly in components

this.$store.commit('setModuleA') || this.$store.commit('setModuleA', ' Parameters ')

Use in components mapMutations mapping

import { mapMutations } from 'vuex'

methods: {
    ...mapMutations([
        openFn: 'setModuleA'
    ])
}

Internal to the module mutations, First parameter accepted by default state Is the local state object of the module

const moduleA = {
    mutations: {
        setModuleA(state) {
            state.xxx += 'xxx'
        }
    }
}

If you need to take parameters

const moduleA = {
    mutations: {
        setModuleA(state, value) {
            state.xxx += value
        }
    }
}

8.5, Use modules Of the injection module actions

Use... Directly in components

this.$store.dispatch('xxx')

Use in components mapActions mapping

import { mapActions } from 'vuex'

methods: {
    ...mapActions([
        'moduleA'
    ])
}

Or rename

import { mapActions } from 'vuex'

methods: {
    ...mapActions({
        fn: 'moduleA'
    })
}

For internal action, Local state pass context.state Exposed , The root node status is context.rootState

const moduleA = {
  // ...
  actions: {
    fn ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

8.6, Namespace

By default , Internal to the module actionmutation and getter Is registered in the global namespace , This allows multiple modules to be on the same mutation or action A response . If you want the module to have higher encapsulation and reusability , You can add... To the module namespaced: true To make it a module with a namespace . When the module is registered , All of it getteraction And mutation Will automatically adjust the name according to the path registered by the module .

8.6.1, Use

First in the module moduleB.js Add namespaced: true

const moduleB = {
    namespaced: true,
    state: () => ({
        b: ' I am a moduleB'
    }),
    mutations: {},
    actions: {},
    getters: {}
}

export default moduleB

stay store Of index.js in

import moduleA from './modules/moduleA'
import moduleB from './modules/moduleB'

export default new Vuex.Store({
    state: {},
    getters: {},
    mutations: {},
    actions: {},
    modules: {
        moduleA,
        moduleB
    }
})

If you use namespaces in components , You need to bring the space name ,mapState, mapGetters, mapMutations,mapActions Use the same .

<script>
import { mapState, mapGetters, mapMutations } from 'vuex'

export default {
    name: 'Vuex',
    data() {
        return {}
    },
    computed: {
        //  What's injected here is moduleA Module data 
        ...mapState('moduleA', [
            'a'
        ]),
        //  Need injection moduleB modular , Just write another 
        ...mapState('moduleB', [
            'b'
        ])
    },
    mounted() {
        //  Use it directly 
        console.log(this.$store.state.moduleA.a)
        console.log(this.$store.state.moduleB.b)
    },
    methods: {}
}
</script>

8.6.2 , Access global content within a module with a namespace

If you want to use global state and getter,rootState and rootGetters Will be passed in as the third and fourth parameters getter, Also through context Object's properties passed in action. If you need to distribute within a global namespace action Or submit mutation, take { root: true } As the third parameter to dispatch or commit that will do

const moduleA = {
    namespaced: true,
    state: () => ({
        a: ' I am a moduleA'
    }),
    getters: {
        getModuleA(state, getters, rootState, rootGetters) {
            //  Using the global namespace state or getters
            return state.a + rootState.count
        }
    },
    mutations: {
        setModuleA(state) {
            console.log(state.a)
        }
    },
    actions: {
        addM({ state, commit, dispatch, rootState, rootGetters }) {
            console.log(rootState)
            console.log(rootGetters)
            //  Call the method of the global namespace 
            dispatch('rootFunction', null, { root: true })
        }
    }
}

export default moduleA

8.6.3, Register the global... In the module with namespace action

Register the global... In the module with namespace action, Need to add root: true, And will the action The definition of is in the function handler in , among ,handler The first parameter of namespacedContext Namely action Medium Context Parameters

const moduleA = {
    namespaced: true,
    state: () => ({
        a: ' I am a moduleA'
    }),
    getters: {},
    mutations: {},
    actions: {
        rootFn: {
            root: true,
            handler(namespacedContext, param) {
                console.log(namespacedContext.state)
            }
        }
    }
}

export default moduleA

If you read it and find it helpful , I am a @ Peng Duoduo , welcome give the thumbs-up Focus on Comment on ;END

The articles

Personal home page

copyright notice
author[Peng Duoduo],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210826214940688y.html

Random recommended