vuex知识笔记,及与localStorage和sessionStorage的区别
菜单快捷导航
- Vuex是什么东东,有什么应用场景?localStorage和sessionStorage能否替代它?
- Vuex知识点State、Getter、Mutaion、Action
- Vuex模块化(Module)
1、Vuex概念和应用场景
首先,Vuex是什么,官网介绍说Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。我的理解就是Vuex就是类似于sessionStorage这样管理数据(本地存和取)的一种技术方案。
既然vuex类似于sessionStorage,那为何我们还要学习vuex,直接用sessionStorage和localStorage不就好了?这个问得好,我来描述一种场景:多个视图(view)组件都要用到某一条数据(状态),当这条数据发生变化的时候,依赖于该数据(状态)的相关视图(view)都要跟着即时更新。这种场景在工作中非常常见,我说一个自己碰到的例子,以前有一个react项目,其中有个功能是在pc页面自定义小程序页面,然后整个PC页面有三个组件组成,在三个组件中还有其他的很多子组件。然后一开始的做法就是通过事件和组件间传值来进行整个页面数据同步更新,后面随着组件越来越多,功能越来越复杂,麻烦和问题也就越来越多。然后每一个后面来接手的同事看代码都要看好一阵,长痛不如短痛...
对的,在工作中这种常见的多个组件依赖于同一条数据(状态),需要即时响应更新的情况,vuex的价值就体现出来了。这种情况下,vuex相比其他实现手段,就要简单干脆方便多了!先看一个小例子,看看vuex和localStorage、sessionStorage的区别,上图:

如图,vuexPageA页面中引用了三个组件,每个组件都分别从localStorage、sessionStorage、vuex中取了一个值。点击按钮加1的时候,vuex的值是及时更新了,其他需要刷新才能更新。总结一下:
- localStorage存储的值能够永久的存储在浏览器上。不管是重新打开新窗口还是重启,同一个浏览器上的相同域名下,localStorage的值一直在。
- sessionStorage存储的值依赖于当前窗口(当前会话), 只要当前窗口不关闭,它存储的数据就一直在。一旦关闭窗口或者打开新窗口,sessionStorage之前存储的数据就会消失。
- 相比localStorage和sessionStorage,vuex存储的数据可以即时更新到,当前项目下的所有引用了该数据的组件。但是如果刷新页面的话,vuex存储的值会重置,而localStorage和sessionStorage存储的值不会重置。
相关代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageA.vue
2、Vuex知识点State、Getter、Mutaion、Action
2.1 Vuex之State和mapState
每一个Vuex应用的核心就是store(仓库),“store"基本上就是一个容器。Vuex使用单一状态树,相当于用一个对象(store)就包含了全部的应用层级状态,也就是说每个应用也只包含一个store实例。因此Vuex的使用从new一个Vuex.Store实例(store实例)开始。store实例中的State属性就是用来存放Vue应用的所有的状态。先来看要给最简单的包含State属性的store实例:
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex) export default new Vuex.Store({
state: {
count: 0,
},
})
后面的mutations、getters、actions再慢慢往里面加入代码。
store实例创建,如何应用?Vue实例创建时,提供了一个store选项,可以让Vuex通过store选项,将store实例对象从根组件”注入“到每一个子组件中:
import Vue from 'vue'
import App from './App.vue'
import router from './router.js' //vuex 之 store实例对象
import store from './api/store/index' new Vue({
router,
store, // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
render: h => h(App)
}).$mount('#app')
store实例注入根组件后,应用中的每个组件中通过this.$store指的就是该store实例对象。那么现在如何在Vue组件中展示store中的state状态(数据)呢?由于Vuex的状态存储是即时响应的,从store实例中读取状态最简单的方法就是在Vue组件中”计算属性“computed中返回某个状态。每当store.state中某个状态变化的时候,都会重新求取计算属性,并且触发更新相关联的DOM。
mapState是一个辅助函数,当我们应用中一个组件需要获取store中多个状态的时候,使用mapState辅助函数可以帮助我们更加方便生成计算属性。看看下面的应用测试代码:
import { mapState } from 'vuex';
export default {
data(){
return {
localCount: 88
}
},
mounted(){
console.log("...store对象:", this.$store);
},
computed:{
localStorage_count(){
return localStorage.getItem('localStorage_count')
},
//使用对象展开符"...",可以将对象目标对象混入到外部对象中
...mapState({
sessionStorage_count(){
return sessionStorage.getItem('sessionStorage_count')
},
vuex_count: state => state.count, //箭头函数可以使代码更简练
vuex_count_alias: 'count', //传字符串参数'count'等同于 state => state.count
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
}),
},
}
2.2 Vuex之Getter和mapGetters
有时我们需要从store中的state种派生出一些状态,比如对store中的某一个状态(数据)进行筛选过滤,然后特别是当有多个组件需要用到这种状态(数据)时,“getter"就出场了!Vuex允许我们在store中定义”getter"(可以认为是store对象的计算属性)。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter接受state作为其第一个参数:
export default new Vuex.Store({
state: {
count: 0,
todos: [
{ id: 1, text: '金戈铁马,气吞万里如虎', done: true },
{ id: 2, text: '老骥伏枥,志在千里', done: false },
{ id: 3, text: '周公吐哺,天下归心', done: true },
{ id: 4, text: '但使龙城飞将在,不教胡马度阴山', done: false },
]
},
//Vuex允许我们再store中定义"getter"(可以认为是store的计算属性)。
// 就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters: {
doneTodos: state => {
console.log('...state.getters.donwTodos...')
return state.todos.filter(todo => todo.done)
},
//Getter也可以接受其他getter作为第二个参数
//getter在通过属性访问时是作为Vue的响应式系统的一部分缓存其中的
doneTodosCount: (state, getters) => {
console.log('...state.getters.doneTodosLength...', getters.doneTodos)
return getters.doneTodos.length;
},
//通过方法访问:通过让getter返回一个函数,来实现给getter传参。
//getter在通过方法访问时,每次都会去进行调用,而不会缓存结果。
getTodoById: (state) => (id) => {
console.log('...state.getters.getTodoById...: ', id);
return state.todos.find(todo => todo.id === id);
}
},
})
Getter应用:Getter会暴露为 store.getters 对象,然后在组件中,我们可以通过this.$store.getters来得到getter。getter里面的属性,可以返回属性,也可以返回方法。如果getter通过属性访问时是作为Vue的响应式系统的一部分缓存,首次调用后再次调用时就会调用缓存,只有该属性的依赖值变化时,再次调用该属性才会重新调用重新缓存。如果getter通过方法访问时,每次都会去进行调用,而不会缓存结果。组件中应用测试代码:
methods:{
//state.getters调用
stateGettersProperty(){ //getters属性调用, 属性调用会被缓存
console.log(this.$store.getters.doneTodos);
console.log(this.$store.getters.doneTodosCount);
},
stateGettersMethod(){ //方法调用,每次都会去进行调用,而不会缓存结果。
console.log(this.$store.getters.getTodoById(2).text);
console.log(this.$store.getters.getTodoById(3).text);
},
addTodo(){ //增加数据
let count = this.$store.state.todos.length;
let obj = {
id: count + 1,
text: (count+1) + '***' + (count+1),
done: count % 2
}
this.$store.commit('addTodos', obj);
},
}
mapGetters也是一个辅助函数,可以将store对象中的getter映射到局部计算属性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
如果你想将一个 getter 属性另取一个名字,使用对象形式:
mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
2.3 Vuex之Mutation和mapMutations
上面说的mapState、getters、mapGetters都是对store对象中的状态(state)进行应用,如果想更改Vuex的store对象中的状态(state),必须要用mutation。Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler) 。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})
mutation里面handler调用通过store.commit来调用,调用方式有“载荷(payload)"和“对象风格”两种方式:
- 载荷提交方式:
// ...
mutations: {
increment (state, n) {
state.count += n
}
}store.commit('increment', 10) - 对象风格提交方式:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}store.commit({
type: 'increment',
amount: 10
})一条重要的原则:mutation必须是同步函数。在组件中使用this.$store.commit('***')提交mutation,或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用。
2.4 Vuex之Action和mapActions
Action类似于mutation,但是Action提交的是mutation,不能直接变更状态;另外Action可以包含任意异步操作。在组件中使用this.$store.dispatch('***')调用action,或者使用mapActions辅助函数将组件中的methods映射为store.dispatch调用。
State、Getter、Mutation、Action的一些应用测试代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageB.vue
3、Vuex之模块化(Module)
由于使用单一状态树,应用的所有状态(数据)会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。为了解决这种问题,Vuex允许我们将store分隔成模块(module)。每个模块都有自己的state、mutation、action、getter、甚至是嵌套子模块。
默认情况下,模块内容的action、mutation和getter是注册在全局命名空间的,这样使得多个模块能够对同一mutation或action作出响应。因此为了让模块具有更高的封装度和复用性,我们可以在每个子模块中添加namespaced: true属性,这样表示该模块成为了带命名空间的模块。这样后面再调用该模块的getter、action和mutation时需要带上该模块名称+调用的属性或方法。下面写一个示例代码:
新建三个js文件moduleA.js、moduleB.js、moduleStore.js,其中moduleA和moduleB分别为子模块。
moduleA.js:
const state = {
countA: 99
}
const mutations = {
increment(state){
state.countA++
},
decrement(state){
state.countA--
}
}
const getters = {
doubleCount(state){
return state.countA * 2
}
}
const actions = {
add({ commit }){
setTimeout(function(){
commit('increment')
}, 50)
},
minus({ commit }){
setTimeout(()=>{
commit('decrement')
}, 500)
}
}
export default {
namespaced: true, //表示设置命名空间
state,
mutations,
getters,
actions
}
moduleB.js:
const state = {
countB: 11
}
const mutations = {
increment(state){
state.countB++;
},
decrement(state){
state.countB--;
}
}
//getters类似state里面属性的计算属性
const getters = {
doubleCount(state){
return state.countB * 2;
}
}
const actions = {
add({ commit }){
commit('increment')
},
minus({ commit }){
commit('decrement')
}
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}
moduleStore.js:
/*
* 当项目大了后,为了责任清晰,目标明确,更易管理,将store拆成多个module形式
* */
import moduleCountA from './moduleA'
import moduleCountB from './moduleB'
import vuex from 'vuex'
import vue from 'vue'
vue.use(vuex) export default new vuex.Store({
modules: {
moduleCountA,
moduleCountB
}
})
再新建一个VuexPageC.vue页面,测试调用,js代码如下:
import { mapGetters, mapActions, mapMutations } from 'vuex'
export default {
computed:{
...mapGetters({
doubleCountA: 'moduleCountA/doubleCount',
doubleConunB: 'moduleCountB/doubleCount'
})
},
methods: {
...mapActions({
//moduleA模块的actions
addCountA: 'moduleCountA/add',
minusCountA: 'moduleCountA/minus',
//moduleB模块的actions
addCountB: 'moduleCountB/add',
minusCountB: 'moduleCountB/minus'
}),
...mapMutations({
//moduleA模块的mutions
incrementA: 'moduleCountA/increment',
decrementA: 'moduleCountA/decrement',
//moduleB模块的mutions
incrementB: 'moduleCountB/increment',
decrementB: 'moduleCountB/decrement'
}),
}
}
页面效果如图:
完整VuexPageC.vue页面代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageC.vue
vuex知识笔记,及与localStorage和sessionStorage的区别的更多相关文章
- vuex存储和本地存储(localstorage、sessionstorage)的区别
1.最重要的区别:vuex存储在内存,localstorage则以文件的方式存储在本地 2.应用场景:vuex用于组件之间的传值,localstorage则主要用于不同页面之间的传值. 3.永久性:当 ...
- localStorage和sessionStorage的区别
//在chrome测试的结果; 知识点1:localStorage和sessionStorage的区别; localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除local ...
- cookie、session、localStorage、sessionStorage的区别
cookie的机制 cookie是存储在用户本地终端上的数据.有时也用cookies,指某些网站为了辨别用户身份,进行session跟踪而存储在本地终端上的数据,通常经过加密. Cookie是服务器发 ...
- localStorage与sessionStorage 的区别
通过一枚页面计数器来区别localStorage与sessionStorage. 通过一个计数变量pageconut,每刷新页面,增加的是localStorage的数量,而sessionStorage ...
- 13.localStorage和sessionStorage的区别
HTMl5的sessionStorage和localStorage html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage. sessionSt ...
- Cookie、LocalStorage 与 SessionStorage的区别在哪里?
基本概念 Cookie Cookie 是小甜饼的意思.顾名思义,cookie 确实非常小,它的大小限制为4KB左右.它的主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”,这通常就是通 ...
- cookie、LocalStorage、sessionStorage三者区别以及使用方式
cookie用来保存客户浏览器请求服务器页面的请求信息 HTML5的WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储) WebStor ...
- cookie、localStorage、sessionStorage的区别
localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 共同点:sessionStorage.localStorage和cooki ...
- localStorage 和 sessionStorage的区别
存储对象: 在主流浏览器中,添加了html5 Web Storage API 的接口,storage是一个存储对象,它包括会话存储(session storage)或本地存储(local stora ...
随机推荐
- 【UEFI&BIOS】---BIOS开机串口报"ERROR: C2:V1050007 IO 93B80003-9FB3-11D4-9A3A-0090273FC14D 6413FA18"的分析
intel的X86 CPU对运行错误的处理已经做的非常完善了,一般即使是开机卡死,跑飞等各种问题也会丢给你相关的提示信息,那么掌握这种错误的分析手段就显得至关重要.在实际开发的过程中,我遇到了一个错误 ...
- vue+jest+vue-test-utils 单元测试
jest是Facebook的一套开源的JavaScript测试框架,它集成了快照测试.断言.mock以及覆盖率报告等功能,很全面而且基本不需要太多的配置便可使用Vue-Test-Util ...
- 让你的 Linux 命令骚起来
目录 管道符号 " | " grep sed awk sort comm uniq tr cat head tail wc find tsort tee 「>」重定向符号 「 ...
- Django 添加 app
一.创建Django项目的时候添加 二.在终端创建app python manage.py startapp app名称 运行完命令后,要在settings.py文件中,添加配置文件
- 力扣337——打家劫舍 III
这一篇也是基于"打家劫舍"的扩展,需要针对特殊情况特殊考虑,当然其本质还是动态规划,优化时需要考虑数据结构. 原题 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃 ...
- [洛谷P3621] [APIO2007] 风铃
Description 你准备给弟弟 Ike 买一件礼物,但是,Ike 挑选礼物的方式很特别:他只喜欢那些能被他排成有序形状的东西. 你准备给 Ike 买一个风铃.风铃是一种多层的装饰品,一般挂在天花 ...
- [bzoj1297] [洛谷P4159] [SCOI2009] 迷路
Description windy在有向图中迷路了. 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1. 现在给出该有向图,你能告诉windy总共有多少种不同 ...
- printf 函数笔记
函数声明 int printf (const char*, ...); 说明 <返回值> printf ("<格式化字符串>", <参数表>); ...
- 创建dynamics CRM client-side (七) - 用JS 来控制Auto-Save
在我们的system setting里面, 我们可以设置打开/关闭 auto save的功能. 我们可以用js来控制auto-save this.formOnSave = function (exec ...
- python读取txt打印(print)出乱码的问题
如下图所示,print第一行首位出现乱码的问题 网上的解答是因为UTF-8的BOM前缀(\xef\xbb\xbf) 解决这个问题的方法很多,最快捷的方法是txt文本另存为的时候更改编码格式 将txt另 ...