Fairy
逼着你往前走的,不是前方梦想的微弱光芒,而是身后现实的万丈深渊。 ---------致自己

vue从入门到精通之【vuex】(七)

vuex一个公用的大仓库,Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。

Vuex 实现了一个单向数据流,在全局拥有一个 state 存放数据,当组件要更改 state 中的数据时,必须通过 mutations 进行,mutations 同时提供了订阅者模式供外部插件调用获取 state 数据的更新。而当所有异步操作(常用于调用后端接口异步获取数据)或批量的同步操作需要走 actions,但 actions 也是无法直接修改 state 的,还是需要通过触发 mutations 中的方法,然后 mutations 来修改 state 的数据。数据变更后相应推送给组件,组件重新渲染到视图上。

vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法是在 vuex 里数据改变的时候把数据拷贝一份保存到 localStorage 里面,刷新之后如果 localStorage 里有保存的数据,取出来再替换 store 里的 state。

核心:State,Getter,Mutation,Action,Module

  1. state:包含了store中存储的各个状态。
  2. getter: 类似于 Vue 中的计算属性,根据其他 getter 或 state 计算返回值。
  3. mutation: 一组方法,是改变store中状态的执行者,只能是同步操作。
  4. action: 一组方法,其中可以包含异步操作。
  5. module:模块化管理

一、安装

npm install vuex --save
yarn add vuex

二、创建仓库store

在src下创建一个store文件夹,在文件夹里面创建一个index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    count: 0,
    name:"zhangsan"
  },
  getter: {
    doneTodos: (state, getters) => {
      return state.todos.filter(todo => todo.done)
    }
  },
  mutations: {
    increment (state, payload) {
      state.count++
    }
  },
  actions: {
    addCount(context) {
      // 可以包含异步操作
      // context 是一个与 store 实例具有相同方法和属性的 context 对象
    }
  }
})

export default store;

修改main.js:

import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store'; // 引入我们前面导出的store对象

Vue.config.productionTip = false;

new Vue({
    el: '#app',
    router,
    store, // 把store对象添加到vue实例上
    components: { App },
    template: '<App/>'
});

最后修改App.vue:

<template>
    <div></div>
</template>

<script>
    export default {
        mounted() {
            // 使用this.$store.state.XXX可以直接访问到仓库中的状态
            console.log(this.$store.state.name); 
        }
    }
</script>

此时,启动项目npm run dev,即可在控制台输出刚才我们定义在store中的name的值。

三、使用

State 类似于vue中的data

Vuex 使用 state 来存储应用中需要共享的状态。为了能让 Vue 组件在 state更改后也随着更改,需要基于state 创建计算属性。

const state = {
  count:"",
  storeId:"",
  storeName:''
}

1.使用

{{this.$store.state.count}} (无缓存,不要用)

2.computed (有缓存)

如果数据没更新,就去缓存中去拿,数据更新就去获取最新的数据

computed: {
     //有数据缓存的功能
     count() {
       return this.$store.state.count;
}}

3.mapState 辅助函数

//导入
import { mapState } from 'vuex'				 
				 
computed:mapState(["count","num","apple"])
				 
computed:mapState({
		c:state => state.count,
			n:"num",
			result(state){
			return state.count + state.num 
			}
		})
				 
computed:{
		...mapState(["count","num","apple"]),
		hw(){
				return "hello world!"
			}
}

注意://不能直接修改(页面数值能变,仓库数值不变),修改通过仓库管理员来处理
this.$store.state.count++;

//通过仓库管理员来处理----》mutations

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

需要以相应的 type 调用 store.commit 方法:

store.commit('increment')

Getter 类似于Vue中计算属性

类似于 Vue 中的 计算属性(可以认为是 store 的计算属性,对Store中的数据进行加工处理形成新的数据),getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

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

1.使用
{{this.$store.getters.donearr}}无缓存不要用

2.computed

computed:{//缓存的作用
	donearr(){
			return this.$store.getters.donearr
	}
}

3.mapGetters 辅助函数

import { mapGetters } from 'vuex'
 
computed: {
    ...mapGetters(['donearr'])
}

Mutations类似于vue中的methods 同步

为什么不能在Mutation中直接异步

Mutation 用于变更 Store 中的数据。

只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据,通过commit一个mutation来修改,它的本质实际是一个function

通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化
mutation 操作一定是同步的

我们每次提交 mutation 都会有一个记录,Vuex 这样做是为了更方便的记下每个数据改变的历史和轨迹,方便监听以及回滚之类的操作

1.使用 js中定义 mutation 通过commit调用

mutations:{
		addcount(state,payload){
		   state.count+=payload;//变更状态
		   }
},
// 在组件中触发 mutation
changecount(){
	//通过仓库管理员来处理
  // 触发 mutations 的第一种方法
this.$store.commit("addcount",{n:100,m:1000});}

2.触发 mutations 时传递参数:

// store.js
mutations: {
    addN(state, step) {  //第一个参数是state,后面的参数是 store.commit 传入的额外参数,即 mutation 的载荷 payload
        state.count += step
    }
}
 
// 组件中
this.$store.commit('addN', 3) // 调用commit函数,触发mutations时携带参数

3.mapMutations辅助函数

// 1. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'
 
// 2. 通过刚导入的 mapMutations 函数,将指定的 mutations 函数,映射为当前组件的 methods 函数
methods: {
    ...mapMutations(['add', 'addN'])
}

Actions 类似于vue中的methods 异步

● Action 提交的是 mutation,而不是直接变更状态。(要通过Mutation)

● Action 可以包含任意异步操作。

vueX:注意:context---》{commit dispatch,state...}

注:不要在 mutations 函数中,执行异步操作,比如添加延时器

只有 mutations 中定义的函数,才有权利修改 state 中的数据;在 actions 中不能直接修改 state 中的数据,必须通过 context.commit 触发某个 mutation。

context:上下文对象,相当于箭头函数中的this,和 store 实例具有相同的属性和方法

payload:挂载的形参

actions:{
		    	   addcountA(context,n){
		    		   console.log(context,n);
		    		   
		    		   setTimeout(function(){
		    		   		context.commit("addcount",n);
		    		   },1000)
		    	   }
		    }

1.使用 通过dispatch

// store.js 中定义 Action
const store = new Vuex.store({
    //...省略其他代码
    actions: {
        addAsync(context, payload) {
            setTimeout(() => {
                context.commit('add')
            }, 1000)
        }
    }
})

// 在组件中触发 Action
methods: {
    handle() {
        this.$store.dispatch('addAsync', 3)
    }
}

2. mapActions 辅助函数

<button @click="changecountA(5000)">修改countA</button>
			
import { mapState,mapActions} from 'vuex'
			
...mapActions({
	changecountA: 'addcountA' // 将 `this.changecountA()` 映射为 `this.$store.dispatch('addcountA')`
})

Modules 模块

可以将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块

namespaced为true的作用是告诉vuex,该模块所有的state 、getters、mutations、actions里面的东西调用时都需要加上命名空间,这个命名空间就是该模块被improt时命名的名字。

//ModuleA.js
const moduleA = {
	namespaced: "true",
	state: {
		msg: "moduleA...",
		name: "lili",
		age: 28
	}
}
export default moduleA;

1.使用

this.$store.state.a.msg;

2.computed

msg() {
      return this.$store.state.a.msg;
 }

3.辅助函数的用法:3种

  • 3.1 箭头函数
import { mapState } from "vuex";

...mapState({
   msg: (state) => state.a.msg,
   name: (state) => state.a.name,
   age: (state) => state.a.age,
})
  • 3.2 数组形式
import { mapState } from "vuex";

...mapState("a",["msg","name","age"])
  • 3.3 通过辅助函数

可以通过使用 createNamespacedHelpers 创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:

import { createNamespacedHelpers } from 'vuex'
const { mapState } = createNamespacedHelpers('a')

...mapState(["msg","name","age"])

四、作用

可以方便的实现组件之间数据的共享

使用 Vuex 统一管理状态的好处:

● 能够在 Vuex 中集中管理共享的数据,易于开发和后期维护

● 能够高效的实现组件之间的数据共享,提高开发效率

● 存储在 Vuex 中的数据都是响应式的,能够实时保持数据与页面的同步

什么样的数据适合存储到 Vuex 中

一般情况下,只有组件之间共享的数据,才有必要存储到 Vuex 中;对于组件的私有数据,依旧存储在组件自身的 data 中即可。

  • 多个视图依赖于同一个状态:例如多组件之间数据共享,在不同页面都可以拿到用户信息

  • 来自不同视图的行为需要改变同一个状态:比如用户会员信息,在不同页面可以更改

posted on 2022-01-02 22:29  Fairy-02  阅读(118)  评论(0编辑  收藏  举报