您的当前位置:首页正文

Vuex 状态管理模式

2024-11-08 来源:个人技术集锦

1. Vuex 是用来做什么的 ?


官方解释: Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式

多个组件中共享状态

2. Vuex 安装


npm install vuex --save

创建文件: src/store/index.js, 文件内容如下:

import Vue from 'vue';
import Vuex from 'vuex';
// 1. 安装插件
Vue.use(Vuex)
// 2. 创建对象
const store = new Vuex.Store({
})
// 3. 导入 store 对象
export default store

再 main.js 中导入 store 对象

import store from './store'
new Vue({
    el: '#app',
    store,
    render: h => h(App)
})

3. Vue.js devtools 浏览器插件


多个界面修改 vuex 状态时,这个工具会对状态进行跟踪,当出现问题时,可以更好的调试错误

4. getters 的使用详解


当某一个数据需要经过一系列的操作后再返回时,可以使用 getters 处理,其作用其实相当于组件的计算属性 computed

const store = new Vuex.Store({
    state: {
        counter: 6
    },
    getters: {
        power(state) {
            return state.counter * state.counter
        }
    }
})

然后在组件模板中可以直接调用 getters 中的 power

{{ $store.getters.power }}

getters 的其他用法参考下方代码示例:

{{ $store.getters.more20Stu }}
{{ $store.getters.more20StuCount }}
{{ $store.getters.moreAgeStu(20) }}
const store = new Vuex.Store({
    state: {
        students: [
            { id: 1, name: "wang", age: 18 },
            { id: 2, name: "liang", age: 21 },
            { id: 3, name: "zhang", age: 30 },
        ],
    },
    getters: {
        more20Stu(state) {
            // 获取年龄大于20的
            return state.students.filter(s => s.age > 20)
        },
        more20StuCount(state, getters) {
            // 获取年龄大于20的个数
            return getters.more20Stu.length
        },
        moreAgeStu(state) {
            // 如果要传参数,需要返回一个函数
            return age => {
                return state.students.filter(s => s.age > age)
            }
        }
    }
})

5. mutations 的使用详解


store 状态更新的唯一方式: 提交 Mutation

Mutation 主要包括两部分: 事件类型 (type)、回调函数 (handler)

mutation 的定义方式:

increment 称为事件类型,回调函数的第一个参数就是 state

mutations 中的方法第二个参数被称为 mutations 的载荷 (payload)

mutations: {
    increment(state) {
        state.counter++
    },
    decrement(state, num) {
        state.counter -= num
    },
}

通过 mutation 更新 state 数据

this.$store.commit("increment");
this.$store.commit("decrement", num);// 传参

通过 commit 进行提交是一种普通的提交方式,vue 还提供了另外一种风格,它是一个包含 type 属性的对象

this.$store.commit({
    type: "add",
    num: 10,
    age: 20,
});

此时要注意 mutation 中的方法的第二个参数的值,和普通提交方式可不一样

add(state, payload) {
    console.log(payload) // {type: 'add', num: 10, age: 20}
}

6. actions 的使用详解


通常情况下, vuex 要求 mutations 中的方法必须是同步方法。主要的原因是当我们使用 devtools 时,devtools 可以帮助我们捕捉 mutation 的快照,但如果是异步操作,那么 devtools 将不能很好的追踪这个操作什么时候完成

基础使用

this.$store.dispatch("update");
const store = new Vuex.Store({
    state: {
        counter: 6,
    },
    mutations: {
        change(state) {
            state.counter += 10
        }
    },
    actions: {
        update(context) {
            setTimeout(() => {
                context.commit('change')
            }, 1000)
        }
    }
})

当需要传递参数时,可使用 dispatch 的第二个参数

this.$store.dispatch("update", {
    name: "liang",
    age: 23,
});
actions: {
    update(context, payload) {
        console.log(payload) // {name: 'liang', age: 23}
        setTimeout(() => {
            context.commit('change')
        }, 1000)
    }
}

因为 actions 中是异步操作,所以当异步操作结束后应该通知外面我已操作完成

this.$store.dispatch("update", () => {
    console.log("异步操作结束");
});
actions: {
    update(context, payload) {
        setTimeout(() => {
            context.commit('change')
            payload()
        }, 1000)
    }
}

当需要传入参数时,可以这样写

this.$store.dispatch("update", {
    payload: {
        name: "liang",
        age: 23,
    },
    success: () => {
        console.log("异步操作结束");
    },
});
actions: {
    update(context, params) {
        console.log(params.payload)
        setTimeout(() => {
            context.commit('change')
            params.success()
        }, 1000)
    }
},

更优雅的写法 Promise:

this.$store
    .dispatch("update", {
        name: "liang",
        age: 23,
    })
    .then((result) => {
        console.log("result: ", result);
    });
actions: {
    update(context, payload) {
        return new Promise((resolve, reject) => {
            console.log(payload)
            setTimeout(() => {
                context.commit('change')
                resolve('异步操作结束')
            }, 1000)
        });
    }
}

7. modules 的使用详解


vue 使用单一状态树,那么也就意味着很多状态都会交给 vuex 管理,当应用变得非常复杂时,store 对象就有可能变得相当臃肿,为了解决这个问题,vuex 允许我们将 store 分割成模块,每个模块拥有自己的 state、mutations、actions、getters 等

// state
{{ $store.state.a.name }}
// getters
{{ $store.getters.name }}
{{ $store.getters.fullname }}
// mutations
this.$store.commit("updateName");
// actions
this.$store.dispatch("save");
const store = new Vuex.Store({
    state: {
        counter: 6,
    },
    modules: {
        a: {
            state: {
                name: 'liang'
            },
            mutations: {
                updateName(state) {
                    state.name = 'zhang'
                }
            },
            getters: {
                name(state) {
                    return state.name + ' 666'
                },
                // 在模块的 getters 中有第三个参数
                fullname(state, getters, rootState) {
                    return getters.name + ' ' + rootState.counter
                }
            },
            actions: {
                save(context) {
                    setTimeout(() => {
                        context.commit('updateName')
                    }, 1000);
                }
            }
        }
    }
})

当我们的 vuex 帮助我们管理过多内容时,好的项目结构可以让我们的代码更加清晰

Top