WEB前端框架Vue3最新vuex状态管理详解及案例解析

1 篇文章 0 订阅

一、Vuex名词解释:

​ 官方解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

​ 白话文:前端多个组件共用一个全局属性 或 模块属性,通过对应状态改变,共享变化,可以作为 前端存储’数据库’用。

二、流程图

在这里插入图片描述

三、安装方式:

1.script标签 直接cdn或下载引入

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

2.npm 或者 yarn

// npm 推荐
npm install vuex@next --save

// yarn 方式
yarn add vuex@next --save

3.vue-cli 命令行创建项目时,选择vuex

J:\test\vue3>vue create my_proj
Vue CLI v4.5.13
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
 (*) Choose Vue version
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
>(*) Vuex
 ( ) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

四、开发插件Devtools

为了更方便快捷的开发vue3项目,强烈推荐大家安装chrome vue.js devtools beta版(支持vue3),目前支持查看组件、状态、路由等。

注:下载需在谷歌商店 下载插件,启用后,f12 调起开发者模式,找到vue

在这里插入图片描述

五、核心概念及案例实现:

1.State状态属性

实现举例代码:

import { createStore } from 'vuex'

export default createStore({
  state: {
    count: 0,
  },
})

模板调用:

{{$store.state.count}}

js实例中调用

console.log(this.$store.state.count)

2.Getter计算属性

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。

Getter 接受 state 作为其第一个参数:

Getter 也可以接受其他 getter 作为第二个参数:(一般用到getters 里面定义的其它计算属性或方法时用到)

案例1.定义属性 返回 数值结果(举例:定义一个getter 计算数值2次方的方法pow)

1./src/store/index.js 定义store计算属性pow

state: {
    num: 0,
},
getters: {
    pow: (state) => Math.pow(state.num, 2),
},

2.模板调用store计算属性

<h2>NUM: {{$store.state.num}}</h2>

案例2:定义属性 返回 回调函数,并利用其他计算属性的返回结果(用到 getters第二个参数)

1./src/store/index.js 定义store计算属性filterGoodsFunc 和 totalPriceFunc(用到了 getters 第二个参数)

state: {
    goods: [
        {
            id: 1,
            name: 'python王者归来',
            price: 300,
        },
        {
            id: 2,
            name: 'js星耀归来',
            price: 160,
        },
        {
            id: 3,
            name: 'node钻石归来',
            price: 90,
        },
    ],
},
getters: {
    filterGoodsFunc: (state) => {
        return (price) => {
            return state.goods.filter(g => g.price > price)
        };
    },
    totalPriceFunc: (state, getters) => {
        return (price) => {
            return getters.filterGoodsFunc(price).reduce((s, n) => s += n.price, 0);
        }
    },
},

3.Mutation 更改属性

更改state状态属性唯一正确方法,需要强调一下,直接更改state也是能实现,但是开发者工具devtools不能同步实时变化,详见上面流程图。

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)**和一个**回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

举例实现:

1./src/store/index.js 中 mutations 定义 inc 自增方法,第一个默认state状态对象,第二个参数可以装载一个或多个参数(json对象实现)

import { createStore } from 'vuex'

export default createStore({
  state: {
    num: 0,
  },
  // 改变状态 通过mutations
  mutations: {
    inc(state, payload){
        // 多个参数,payload 传 json对象
        console.log(payload)
        if(state.num < payload.maxNum){
            state.num += payload.step;
        }
    },
  },
  actions: {
  },
  modules: {
  }
})

2.模板事件 调用mutations方法 改变状态

<button @click="$store.commit('inc',{step: 2, maxNum: 100})">多参数状态传递</button>

3.模板渲染 展示状态值

<h2>获取状态num值:{{$store.state.num}}</h2>

4.Action 事件属性

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

举例实现:

1./src/store/index.js 中 使用 actions token方法 实现网络获取token,并通过mutations 设置token(setToken方法)来改变state 值

state: {
    token: '',
},
mutations: {
    setToken(state, payload) {
        state.token = payload.token;
    },
},
actions: {
    // {commit} 解构赋值语法, 例如:const {commit} = context;
    token({commit}, payload) {
        return new Promise((resolve, reject) => {
          // 这里可以把setTimeout 换成 网络请求服务端接口获取token逻辑
            setTimeout(() => {
                let token = 'aaaaaaaaaaaaaabb';
                commit('setToken', {token});
                console.log(payload);
                let rst = {errcode: 0, msg: 'success', data: {token}};
                if (rst.errcode === 0) {
                    resolve(rst);
                } else {
                    reject({errcode: -1, msg: 'error', data: {}});
                }

            }, 3000);
        });
    }
},

2.模板中js 调用 actions 并传参,多个参数可通过json对象传递,如果actions 返回promise(例如axios请求),可以通过then和catch 链式调用:

methods: {
  getToken(){
    this.$store.dispatch('getToken',{a: 1, b: 2}).then((rst)=>{
      console.log(rst);
    }).catch((err)=>{
      console.log(err);
    });
  }
},

dispatch 方法 可以直接派遣 actions 指定方法 执行调用,并且可以通过第二个参数json对象传递多参数

5.Module 模块属性

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

例如 将用户user 状态管理 分成user模块

/src/store/modules/user.js

代码举例解析:

局部状态调用(模块状态)

store.state.user.xxx // -> user模块的状态

模块的局部状态

1.局部state 要用回调函数返回json对象

state: () => {
    // 这里state 区别 全局状态state定义,而是返回 箭头函数,
    // 函数是有作用域的,保证每个实例相互独立,不会相互影响
    return {
        nickname: '编程热',
        intro: '编程源于热爱',
        token: '',
    };
},

2.对于模块内部的

mutation: 第一个参数为局部状态state对象,第二个参数为传参的对象,多个参数json对象实现。

getter:第一个参数是模块的局部状态state对象,第二个参数为局部计算属性getters,第三个参数为根状态rootState,第四个参数为根计算属性rootGetters

mutations: {
    setNickname(state, payload){
        state.nickname = payload.nickname;
    }
},
getters: {
    getText: (state) => {
        return state.nickname + '-' + state.intro;
    },
    getFullText: (state, getters, rootState, rootGetters) => {
        console.log(rootState); // 根状态
        console.log(rootGetters); // 根getters计算属性
        return getters.getText + ',用心写好每一行代码!';
    },
},

3.对于模块内部的 action 默认参数为context上下文,可以通过解构赋值格式 解析如下

commit, dispatch, getters, rootGetters, state, rootState

actions: {
    getToken({commit, dispatch, getters, rootGetters, state, rootState}, payload) {
        console.log(dispatch);
        console.log(getters);
        console.log(rootGetters);
        console.log(state);
        console.log(rootState);
        return new Promise((resolve, reject) => {
            // 这里可以写请求服务端接口获取token逻辑
            setTimeout(() => {
                let token = 'aaaaaaaaaaaaaabb';
                commit('setToken', {token});
                console.log(payload);
                let rst = {errcode: 0, msg: 'success', data: {token}};
                if (rst.errcode === 0) {
                    resolve(rst);
                } else {
                    reject({errcode: -1, msg: 'error', data: {}});
                }

            }, 3000);
        });
    }
}

4.对于模块内部的modules 可以再嵌套子模块类似当前(不建议子模块再嵌套,可读性差)

      // 嵌套模块
      modules: {
        // 继承父模块的命名空间
        myPage: {
          state: () => ({ ... }),
          getters: {
            profile () { ... } // -> getters['user/profile']
          }
        },
      },

5.命名空间

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

export default {
    namespaced: true,
    state: () => {
    },
    ...
}

启用命名空间后,模板调用的时:

  1. state 调用方式不变
  2. getters.getText --> getters[‘user/getText’]
  3. $store.commit(‘setNickname’) --> $store.commit(‘user/setNickname’)
<p>state.user.nickname {{$store.state.user.nickname}} </p>
<p>text: {{$store.getters['user/getText']}} </p>
<p>fulltext: {{$store.getters['user/getFullText']}} </p>

<button @click="$store.commit('user/setNickname',{nickname:'bian cheng re'})">设置用户名</button>

在带命名空间的模块内访问全局内容(Global Assets)

如果你希望使用全局 state 和 getter,rootState 和 rootGetters 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。

若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

<button 
    @click="$store.commit('user/setNickname',{nickname:'bian cheng re'},{ root: true})">
    设置用户名
</button>

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程热

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值