Vue 知识总结【Vuex】

124 阅读3分钟

Vuex

概念

是什么

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

  1. 状态管理模式:Vuex 提供了一个全局环境,我们可以在这个环境中声明全局变量。这个变量我们称为状态,Vuex 就是管理这个状态(全局变量)。
  2. 集中式:所有的状态都是在同一个地方声明和管理。
  3. 可预测:改变状态(全局变量),Vuex 有固定的方法来改变。

为什么

vuex 是采用集中式管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题。

  • state :声明所有全局变量
  • mutaitionsvuex 提供专门用来修改 state 状态的方法。注意!不可以写异步代码。
  • actionsvuex 提供可以异步修改 state 状态的方法。

总结

image.png

  1. 修改 state 状态必须通过 mutations
  2. mutations 只能执行同步代码,类似 ajax ,定时器之类的代码不能在 mutations 中执行。
  3. 执行异步代码,要通过 actions ,然后将数据提交给 mutations 才可以完成。
  4. state 的状态即共享数据可以在组件中引用。
  5. 组件中可以调用 action

vuex的机制,是一种闭环的状态

使用

环境初始化

  1. 下载依赖
    npm i vuex@3
    
  2. 引入
    import Vuex from "vuex"
    
  3. 注册
    Vue.use(Vuex)
    
  4. 实例化
    const store = new Vuex.Store({
      state: {
        a: 1
      }
    })
    
  5. 挂载
    new Vue({
      // 5、挂载
      // store: store,
      store,
      render: h => h(App),
    }).$mount('#app')
    

1-vuex基本使用.png

state

state 是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state 对象中。

定义

const store = new Vuex.Store({
    state: {
        count: 0
    }
})

使用

原始形式

直接使用插值表达式来获取store对象实例。

<p>{{$store.state.count}}</p>
计算属性

优化使用,将state属性定义在计算属性中。

<p>{{count}}</p>
computed: {
  count(){
    return this.$store.state.count
  }
}

这样可以实现简写。

辅助函数
  1. 引入辅助函数。
    // 引入辅助函数,我们可以通过辅助函数获取store中全局变量
    import { mapState } from "vuex";
    
  2. 在计算属性中使用辅助函数。
    computed: {
      // 这个辅助函数最终解析出来和计算属性优化使用是一样的
      ...mapState(['count']),
    }
    
  3. 在结构中直接使用变量获取 store 中的值。
    <p>{{a}}</p>
    

mutations

state 数据的修改只能通过mutations ,并且 mutations 必须是同步更新,目的是形成数据快照

数据快照:一次 mutation 的执行,立刻得到一种视图状态,因为是立刻,所以必须是同步。

定义

const store = new Vuex.Store({ 
    state: { 
        count: 0 
    }, 
    // 定义mutations 
    mutations: { 
        // 方法里参数 第一个参数是当前store的state属性 
        // payload 载荷 运输参数 调用mutaiions的时候 可以传递参数 传递载荷 
        addCount (state,payload) { 
            state.count += payload 
        }
    } 
})

使用

原始形式

创建一个 button 按钮,点击按钮调用 mutations 内的方法名称。

<button @click="add">点我</button>
methods: {
  add(){
    // 语法:this.$store.commit("mutation中的函数名", 参数1)
    this.$store.commit("setCount",5)
  }
}
辅助函数
  1. 导入 mapMutations
    import { mapMutations } from "vuex";
    
  2. 用数组的形式解构引入。
      methods: {
        ...mapMutations(["setCount"]),
      }
    
  3. 在结构中直接使用方法名,想要传值可直接用括号传值。
    <button @click="setCount(5)">点我</button>
    

注意:

修改数据必须通过 mutations 来修改,如果没有经过 mutations 修改数据,页面上的数据会被修改,但 store 内的数据没有被真正修改。而且在严格模式下还会报错。

action

state 是存放数据的,mutations 是同步更新数据, actions 则负责进行异步操作。

定义

actions: {
    // 定义函数,进行异步操作,通过调用mutations函数从而修改state的值
    asyncCount(context){
      // context:表示当前的store实例
      setTimeout(()=>{
        // 调用mutations中的setCount函数,从而修改count值
        context.commit("setCount",2)
      },1000)
    }
  }

使用

原始形式
methods: {
  setCount(){
    this.$store.dispatch("asyncCount")
  }
}

如果需要传参的话就在后面加个逗号即可,如下所示。

setCount () { 
    this.$store.dispatch('getAsyncCount', 123) 
}

a72c31cceb90dc7f03849b00522d07b.png

辅助函数
  1. 引入辅助函数。
    import { mapActions } from "vuex";
    
  2. actions 中的函数解构到 methods 中。
      methods: {
        ...mapActions(["asyncCount"]),
      }
    
  3. 直接调用函数。
    <button @click="asyncCount">点我</button>
    

ea8b48d6b3d1c82550be9545b281813.png

getters

除了 state 之外,有时我们还需要从 state 中派生出一些状态,这些状态是依赖 state 的,此时会用到 getters

定义

getters: {
  // 定义函数,并且函数可以默认接受到state参数
  // 这个函数名当做普通变量进行使用的
  fileList(state){
    return state.list.filter(item=>item>5)
  },
  student(state){
    return state.obj.student.home
  }
},

使用

原始形式
  1. 操作数据
    <p>{{$store.getters.fileList}}</p>  // [6,7,8,9]
    
  2. 简化步骤
    <p>{{$store.state.obj.student.home}}</p>  // zhanjiang
    <p>{{$store.getters.student}}</p>  // zhanjiang
    

8ca06731f6bafa099fb1d4f3f4acf51.png

辅助函数
  1. 引入辅助函数。
    import { mapGetters } from "vuex";
    
  2. 利用辅助函数把getters中的数据解构为计算属性。
    computed: {
      ...mapGetters(["fileList"]),
    },
    
  3. 使用计算属性展示数据。
    <p>{{ fileList }}</p>
    

d6d1bece7332a5ee7d146ff1cbba9ce.png

modules

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

即如果把所有的状态都放在 state 中,当项目变得越来越大的时候,Vuex 会变得越来越难以维护。

由此,又有了Vuex的模块化

定义

const store = new Vuex.Store({
  modules: {
    // user模块
    user: {
      state: {
        token: '1234'
      }
    },
    // setting模块
    setting: {
      state: {
        name: 'vuex实例'
      }
    }
  }
})

使用

原始形式
<!-- 如何获取模块中的数据进行使用? -->
<!-- 答:通过以下语法:this.$store.模块名.变量 -->
<h1>token: {{$store.state.user.token}}</h1>
<h1>name: {{$store.state.setting.name}}</h1>
辅助函数
  1. 通过getters获取模块中的数据。
    getters: {
      token(state){
        return state.user.token
      },
      name: (state)=>{ return state.setting.name }
    }
    
  2. 利用getters的辅助函数,将数据变量解构为计算属性。
    <script>
    import { mapGetters } from "vuex";
    export default {
      computed: {
        ...mapGetters(["token","name"])
      }
    }
    </script>
    
  3. 使用计算属性。
    <h2>简写token: {{token}}</h2>
    <h2>简写name: {{name}}</h2>
    

cb9861462a2e01907e756bf8a285f54.png

高封闭性

默认情况下,模块中的 mutationsactionsgetters 都是注册在 vuex 全局下的,和写在外面的引用方式是一样的。

如果取一样的名字,会造成冲突的风险。

如果我们想保证内部模块的高封闭性,我们可以采用 namespaced 来进行设置。

// 能够拿到数据
<button @click="$store.commit('setName')">测试直接调用模块中的mutations函数</button>

<script>
const store = new Vuex.Store({
  modules: {
    // setting模块
    setting: {
      state: {
        name: 'vuex实例'
      },
      mutations: {
        setName(state) {
          console.log(state);
        }
      }
    }
  },
})
</script>
作用

使得模块内的 mutationsactionsgetters 等变成局部属性。

使用
直接调用
setting: {
  namespaced: true,
  state: {
    name: 'vuex实例'
  },
  mutations: {
    setName(state) {
      console.log(state);
    }
  }
}

现在直接拿会报错,提示找不到这个函数。

如何获取局部中的 mutations 函数呢?

在调用前需要加模块名,语法如下所示:

$store.commit('模块名/函数名')

中间用逗号隔开。

<button @click="$store.commit('setting/setName')">测试直接调用模块中的mutations函数</button>

现在就能获取到函数了。

b5125cd3e139308b63b2f997390f9fd.png

辅助函数
<button @click="updateToken">测试辅助函数调用模块中的mutations函数</button>

methods: {
  ...mapMutations("user",["updateToken"])
}

630cc3ac5283bd598d606d559e9f1eb.png

createNamespaceHelpers

命名空间的辅助函数

  1. 引入命名空间辅助函数。
    import { createNamespacedHelpers } from "vuex";
    
  2. 通过命名空间辅助函数传入模块名,从而获得到该模块的mutations辅助函数,并重命名。
    const { mapMutations:usermap } = createNamespacedHelpers("user")
    
  3. 利用获取到的mapmutations辅助函数获取到user模块的函数。
    methods: {
      ...usermap(["updateToken"])
    }
    
  4. 直接使用。
    <button @click="updateToken">测试辅助函数调用模块中的mutations函数</button>
    

630cc3ac5283bd598d606d559e9f1eb.png

拓展:解决重名问题

  • computed中原来的属性名和getters中的名字重名。
  • 自定义函数和引入的辅助函数重名。

c0e7df52faee4a7f421e8413e370519.png

vuex的封装

147d06a206f2b70b584ad3acd20cdb1.png