vuex学习记录

118 阅读4分钟

vuex 状态管理插件

可以理解为,把需要多个组件共享的变量全部存储在一个对象里面。

image.png

Vuex 主要解决的问题

  • 多个视图依赖同一个状态
  • 来自不同视图的行为需要变更同一个状态

使用 Vuex 的好处

  • 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
  • 能够高效地实现组件之间的数据共享,提高开发效率
  • vuex 中的数据都是响应式的

使用 Vuex 的使用场景

  • 比如说用户登录,token令牌。在去服务器发送请求的时候需要携带令牌,不是所有用户都给你请求的,只针对登录后的用户给你请求。
  • 比如,用户的头像、地理位置;商品的收藏、购物车中的物品。

安装 Vuex

  • npm install vuex --save(不加-dev因为生产环境也需要用到vuex)
  • 插件一般在main.js中引用,但vuex的东西比较多,我们一般会像引入router一样,我们在src里建一个文件;

通常在src下建名为仓库:store(仓库)的文件,在store文件的index.js里进行创建对象,导出等工作,然后再在main中引入 store下面的index.js:

import Vue from "vue"; 
import Vuex from "vuex"; // 引用 
Vue.use(Vuex); // 使用

// 导出store独享 
export default new Vuex.Store({ 
    // 这边要注意,不是直接new一个Vuex就行了,而是Vuex里面有个属性叫Store,传入一些想要的参数     
    state: {}, // 保存状态的,把它想象成data{}   
    mutations: {},   // 想象成methods
    actions: {},   // 需要处理异步的方法
    getters: {},   // 想象成计算属性computed
    modules: {} // 模块
});

main.js:

import Vue from 'vue'
import App from './App'
import store from './store'
new Vue({   
    el'#app',   
    router,   
    store,   
    i18n,   
    renderh => h(App) 
})

Vuex核心概念:

vuex提出使用单一状态树,英:Single Source of Truth。vue推荐你只使用一个store,不要去搞一大堆的store,不方便以后维护。

  • State:保存共享状态的地方。姑且可以当作是data中的属性。在组件中使用state:$store.state.属性

  • Getters:类似于组件里面的计算属性,定义在vuex里

计算属性:当我的某一个数据经过一系列变化以后再在我们界面上展示的时候,可以用计算属性。

  • 传参:可以接受两个参数例如(state,getters),getters是getters下的方法

  • 组件中调用:{{$store.getters.moreAgeStu(8)}}

    state:{
        students:[{name:'lihua',age:30},{},{}...]
    },
    getters:{
        // 筛选出年龄大于18的学生
        more20stu(state){
            return state.students.filter(item => item.age > 20)
        },
        // 筛选出年龄大于18的学生的长度,可以传参,使用more20stu
        // 可以接受两个参数,getters可以获取getters下的方法
        more20stuLength(state,getters){ 
            return getters.more80stu.length
        },
        //筛选出年龄大于age的学生,age是可以传参的
        moreAgeStu(state){
            // return function(age){
               // return state.students.filter(s => s.age >age)
            // }
             return age=>{
                 return state.students.filter(s => s.age >age)
             }
        }
    }

    // 组件中使用:
    {{$store.getters.more20stu}}
    {{$store.getters.more20stuLength}}
    {{$store.getters.moreAgeStu(8)}}
  • Mutation:方法可以看作是methods,如果想要改变变量,要通过mutation方法,这样devool里可以跟踪到数据的变化。

在通过mutation更新数据的时候,有可能我们希望携带一些额外的参数, 参数被称之为mutation的载荷payload。

  • 传参:

  • 普通:可以接受两个参数例如(state,count),count是传参,可以是很多格式。

  • 特殊:changeCount(state,payload){ state.count = payload.count}payload 是一个对象

  • 组件methods里调用(有两种风格):

  • 普通:this.$store.commit('incrementCount',count)

  • 特殊: this.$store.commit({ type:'changeCount', count:100 }) type事件类型count传参

// 普通的提交方式
mutation:{
    incrementCount(state,count){
        state.couter += count 
    },
    addStudent(state,stu){
        state.students.push(stu)
    }
}

// 组件的methods里,  @click='addCount(8)' count 加8 
// 普通的提交方式 commit(方法名字,传参)
addCount(count){
    this.$store.commit('incrementCount',count)
},
// @click='addStudent' 新增一项
addStudent(){
    const stu = {id:115, name:'alan',age:35}
    this.$store.commit('addStudent',stu)
}


// mutation的另一种提交风格
// 把我们提交的东西全部放到一个对象里面,设置提交类型(上面的incrementCount)的时候,可以在对象里面添加一个属性type

this.$store.commit({
    type:'changeCount', // 事件类型
    count:100 // 传参
})

// 这种提交风格 需注意组件中methods的写法
changeCount(state,payload){
    console.log(payload) // payload是个对象,打印可以发现{type:'changeCount',count:100}
    state.count = payload.count 
}

mutation 上面通过commit进行提交是一种普通的方式,还提供了另外一种风格,他是一个包含type属性的对象。需要注意payload是一个对象了。

  • 思路:
  • 在mutation中,我们定义了很多事件类型(也就是方法名称),当我们的项目增大时,Vuex管理的状态越来越多,需要更新状态的情况越来越多,mutation中的方法越来越多
  • 由于store里面的index.js中,mutations的方法名,会跟在组件中commint调用的方法名一样,所以官方推荐写成一个常量
  • 把mutations抽出来,在store文件里面新建一个mutations-type.js

只有文件export default 才可以import 起个名字 from './compontes/HelloVuex'; 没有export default (export const的形式) :import { } from './compontes/HelloVuex'

两种mutation风格的写法:

image.png

项目中,通常把mutations里的方法大写

  • Action:异步操作

    通常情况下,Vuex要求我们mutation中的方法必须是同步方法

主要的原因是当我们使用detools时,可以devtools可以帮助我们捕捉mutation的快照

但是如果是异步操作,那么devtools将不能很好的跟踪这个操作什么时候会被完成

如果你在mutations使用异步方法例如setTimeout,那么就会出现devtools里面跟踪不了数据的问题

Action类似于Mutation,但是是用来代替Mutation进行异步操作的。

  • 传参:

  • 可以接受两个参数例如 aUpdateInfo(context,payload) ,context是 上下文(跟getters的第二个参数getters不同,注意区分,这里的context是能获取到mutations里的方法类型),payload是 传参

  • 组件里调用:

  • this.$store.dispatch('aUpdateInfo','我是传参') mutation 是commit,actions是dispatch

mutations:{
   updateInfo(state){
       state.info.name = 'coder'
   } 
},
// Action:异步操作里再通过Mutation修改我们的状态
actions:{
    // actions 参数context 上下文
    aUpdateInfo(context,payload){
        setTimeout(()=>{
            context.commit('updateInfo')  // 调用上面的mutations里的方法
            console.log(payload) // 打印出 我是传参
        },1000)
    }
}

// 组件中使用
updateInfo(){
    this.$store.dispatch('aUpdateInfo','我是传参')  // mutation 是commit,actions是dispatch
}

补充一下actions的写法:

    actions:{
        // context 对象的解构写法 {state,commit,rootState}
        // 这里的rootState是指整个 Vuex Store 中所有模块的状态集合,可以用于跨模块访问数据
        incrementSum({state,commit,rootState是指整个 Vuex Store 中所有模块的状态集合,可以用于跨模块访问数据}){
            if((state.count = rootState.count) % 2 ===1){
                commit('increment')
            }
        }
    }
    
  
  • Module:模块
// 由于vue使用单一状态树,state内容会很多,变得臃肿,推荐使用模块
// 每个模块都可以拥有自己的state,mutaitons,actions,getters
modules:{
    a:{
        state:{},
        mutaitons:{},
        actions:{},
        getters:{}
    },
    b:{
        ....
    },
}

// 定义模块使用后,用到state里的name属性,需要$store.a.state.name 
// mutations 和 getters 可以不用.a直接使用

image.png

vuex文件夹的目录组织

image.png

image.png