Vuex入门教程快速入门简介

11 篇文章 2 订阅

Vuex入门教程快速入门简介

什么是Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
他相当于Vue的共享数据层 / 共享内存,当你需要开发业务涉及到数据需要跨页面,跨组件时,使用Vuex比使用参数传递,要方便得多。
可以说,当你需要开发一个稳定可靠的vue项目(现在应该很少有单页面的vue项目了),你就必然用到vuex。

官网:https://vuex.vuejs.org/zh/

Vuex可以干什么

1.高效的实现不同组件间的数据共享和交互。
2.规范数据的操作,使得model层代码基本统一在一个地方,这使得你的项目结构更加清晰,便于维护升级。
3.利用vue Devtools监控数据变化,方便调试,实现time-travel等高级调试功能。

工作流程

vuex的作用和模块可以从其工作流程图上反映出来。
在这里插入图片描述

核心概念

安装

npm install vuex --save

或者

yarn add vuex

模块化打包系统中(例如webpack),还需要调用如下代码,才能真正安装。

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

全局初始化多模块Store

一般情况下,推荐在全局给根组件注册vuex,从而给所有组件使用上vuex,后面的介绍中,我们也跳过那些在官网介绍中,分别给单独页面写vuex的情况,因为那种方式并不实用。
一般情况下,项目很容易用到多个模块,所以默认推荐的初始化方法,是多模块初始化
文件src/store/index.js如下,其中state,actions,mutations,getters的具体内容该怎么写,在后文有介绍,此处省略。

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

const context = require.context(".", true, /\.js$/);
const moduleStores = {};
context.keys().forEach(key => {
  if (key === "./index.js") return;
  const funname = key.replace(/(.*?\/)(\w*)(\.js)/, "$2");
  const v = context(key).default;
  moduleStores[funname] = {
    ...v,
    namespaced: true,
  };
});

const rootStore = {
	state:{
	},
	actions: {
	},
	mutations: {
	},
	getters: {
	}
}
export default new Vuex.Store({
  ...rootStore,
  modules: {
    ...moduleStores,
  },
});

注意要在项目初始化的时候,使用这个文件,因此在main.js或者app.js文件中添加如下代码:

import store from "@/store";
new Vue({
  el: '#app',
  store: store,//确保store功能被添加
})

当项目数据有多个模块时,在src/store/文件夹下增加其他模块(模块名称将和文件名称一致),文件内容如下:

const state = {
	testdata:{},
}
const actions = {
	async getTestData({commit, state, dispatch }, config = {}){
		这里调用api,然后调用commit("setTestData",result);
	}
}
const mutations = {
  ["setTestData"](state, data){
    state.testdata= data;
  },
}
const getters = {
  ["getTestData"](state) {
    return state.testdata;
  },
}
export default {
  namespaced: true,
  state,
  actions,
  mutations,
  getters,
};

State单一状态树

所有的应用级状态(所有的共享数据)都存储在这个实例上。他是唯一数据源(SSOT)。
State中的数据和Vue中的data遵循相同规则。
以下是vue页面/组件中多种使用state中数据的方式:
1.在computed中单个属性指定。

computed: {
    count () { return this.$store.state.count }
  }

2.在computed中使用mapState批量指定(推荐用法)

import { mapState } from 'vuex';//需要先引入辅助函数
export default {
	//......
	computed: {
		...mapState({
			count:state => state.count,
			countAlias: 'count',		//和count一样
			userData:state => state.user.userData,		//绑定user模块中的userData
			doneTodosCount(state){		//进行数据计算并返回
			    return state.todos.filter(todo => todo.done).length
			},
		}),
		localComputed(){},
	}
	//......
}

Getter计算属性

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
例如前文中进行数据计算的doneTodosCount
如果定义在getters里面大概就是这样:

getters:{
  ["doneTodos"](state) {//求数组
    return state.todos.filter(todo => todo.done)
  },
  doneTodosCount: (state, getters) => {//把别人的getters作为第二个参数
    return getters.doneTodos.length
  },
  getTodoById: (state) => (id) => {//查询数据,返回的实际是一个函数,可以在vuex模块内其他函数使用,也可以外部调用
    return state.todos.find(todo => todo.id === id)
  },
}

这时,可以在任意组件中直接使用这个值,例如computed中:

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

也可以通过mapGetters批量获取数据(推荐用法)

import { mapGetters } from 'vuex'
export default {
	//...
	computed: {
		...mapGetters({
			doneTodos:"doneTodos",
			doneTodosCount:"doneTodosCount",
			getTodoById:"getTodoById",
		}),
	},
}

可以在js函数中查询数据

store.getters.getTodoById(2); //vuex模块内调用 -> { id: 2, text: '...', done: false }
this.$store.getters.getTodoById(2);//外部调用

这个写法相对于直接使用mapstate的最大好处,是不用在view层去计算值(切换页面不会导致重新计算),仅当数据发生变化时,计算数值。

Mutation更改状态

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
store/index.js文件或者模块文件中定义如下:

mutations:{
	increment (state) {
		state.count++;
	},
	["setTestData"](state, data){//以对象方式提交荷载 [Payload]
		state.testdata= data;
	},
}

使用如下,任意地方调用如下语句:

this.$store.commit('increment');
this.$store.commit('setTestData', data);

也可以使用mapMutations批量定义函数,然后直接调用函数:

import { mapMutations } from 'vuex'
export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      setTest: 'setTestData' // 将 `this.setTest(data)` 映射为 `this.$store.commit('setTestData', data)`
    })
  }
}

需要注意的是:
1.mutation必须是同步函数,尽量简单,没有复杂计算过程。
2.严格模式下,页面需要通过commit才可以修改数据,但是不推荐这样做,因为要写的代码太多了,一般是通过v-model的功能将view上的数据直接与state中的数据绑定,直接修改。因此,实际上页面/组件上一般用不到commit,mapMutations等相关功能。
3.Mutation 需遵守 Vue 的响应规则。当使用commit('setTestData', data)的时候,data与原有值不能是同一个对象,否则会导致界面无法自动更新,推荐的写法在以下方法中二选一,
a).函数内,想办法触发更新

Vue.set(obj, 'newProp', 123);
//或者
state.obj = {...state.obj, newProp: 123}

b).函数外,提交时就是新对象

commit("setTestData", JSON.parse(JSON.stringify(data)));
//或者
commit("setTestData", {...data});

Actions发起动作

从流程图中,很容易理解到,代码应当使在页面/组件响应时通过dispatch调用Actions,然后在Actions里异步访问API,回调时通过commit调用Mutation修改State,然后反映到界面变化上来。
当然也可以封装一些同步调用的Actions,调用时候计算数据,然后commit

actions:{
  //远程调用
  async tryDoAction({commit, state, dispatch }, config = {}){
  	//发起远程调用,然后回调中修改数据层
	this.$api.api_xxx.tryDoAction(config).then(res=>{
		commit("setTestData", result.data);
	})
  },
  //本地调用-->直接修改数据
  localAction({commit, state, dispatch}, data = {}){
	data.p = 3.1415926;//数据调整
  	commit("setTestData", {...data});//确保界面刷新
  },
  //连环调用
  async actionA ({ commit, state, dispatch }) {
    commit('gotData', await getData())
  },
  async actionB ({ commit, state, dispatch }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

别看Actions这块的介绍短,实际开发的过程中,大部分用户操作,都是在调用actions,然后产生远程调用,所以这块代码会比较多。

从vuex3到vuex4

主要是适应vue3.x版本,vuex需要升级到vuex4.x以上版本,参考官方文档:
https://next.vuex.vuejs.org/guide/migrating-to-4-0-from-3-x.html

其他文档

VUE入门指北
VUE入门指北——(2)MVVM、数据、方法、生命周期
VUE入门指北——(3)单文件组件.vue文件

其他参考资料

知乎 Vuex,从入门到入门
简书 VueX(Vue状态管理模式)
cnblogs 五分钟搞懂Vuex

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值