详解Vuex常见问题、深入理解Vuex

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

  状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。

  使用Vue开发项目时,通常我们就会遇到如下几种棘手的问题:

  问题1:通过路由传递参数,我们会采用params或者query形式,但这两种方式都会在URL上做手脚,如果传递的参数过多,会导致400 Bad Request(如:点击表格某行,携带行数据跳转到新页面进行查看)。 

  问题2:兄弟组件传值 

  问题3:多处地方使用同一数据,为节省重复请求(最为常见)

  业务场景:

  从A页面携带下钻参数(ID)到B页面,然后B页面获取参数(ID)进行数据请求。由于要下钻的ID过长,受浏览器的URL长度限制问题,我们不能采用常规的prams(xxx.com/B/:ID)或query(xxx.com/B?ID=…)形式传递。可以使用Vuex做中间过渡,跳转前存储ID信息,进入B页面后从Vuex获取ID信息。

  如果用户在B页面刷新数据,则Vuex的ID状态值会被清空无法获取,这里只能借助localStorage进行持久化进行处理(当然,如果直接使用localstorage进行持久化存储,而不借助Vuex也是可行的,但就是没了响应式的效果了)

一、常见使用问题

1、Vuex,每次调用mutation之后向localstorage存值,防止刷新丢失

export default {state:{reportInfo:null},getters:{reportInfo(state){if(!state.reportInfo){state.reportInfo = JSON.parse(sessionStorage.getItem('reportInfo'))}return state.reportInfo}},mutations:{initReport:(state,data) => {state.reportInfo = datasessionStorage.setItem('reportInfo',JSON.stringify(data))},changeReportReview:(state,data) => {state.reportInfo.is_review = data;//改state的reportInfo里的某个值,
同时修改sessionStorage的值,以保证一样sessionStorage.setItem('reportInfo',JSON.stringify(state.reportInfo))}}
}

 

2、调用时需要追加模块名称

  如上的getters,首先从store中获取,如果store中不存在则从localstorage中获取(刷新)

3、页面中如果有用户登出操作,此时一般需要removeItem,如果页面中有userInfo的判断信息,如下一般需要先做个判断userInfo存在才会去取userInfo.roleName的值,这样就会防止页面报错,类似于后台语言空指针的错误

<span class="el-dropdown-link">{{userInfo ? (userInfo.account ? userInfo.account : userInfo.phoneNum) : ""}}<i class="iconfont icon-user"></i>
</span>
<router-link :to="'/account'" v-if="userInfo && userInfo.roleName === 'sys'"><el-dropdown-item>添加账户</el-dropdown-item>
</router-link>

  如果没有removeItem的操作的话,则是不需要这样的。如下面的reportInfo,因为用户登出的时候,不会影响到它

<div class="suggess_requert" v-if="suggess.suggestion_level === 3"><div v-if="reportInfo.is_review === 1"><router-link v-if="userInfo && userInfo.roleName === 'dba'" :to="'/list/review'"><h3>提交审核意见</h3></router-link><h3 v-else>专家正在审核,请稍后</h3></div><router-link v-else-if="reportInfo.is_review === 2" :to="'/list/reviewInfo/' + reportInfo.report_id"><h3>查看云和恩墨专家团队审核意见</h3></router-link><div v-else><h3 v-if="userInfo && userInfo.roleName === 'user'" @click="reviewRequest()">一键请求云和恩墨专家团队帮您二次审核</h3></div>
</div>

 

 

4、state访问状态对象

  const state ,这个就是我们说的访问状态对象,它就是我们SPA(单页应用程序)中的共享值。

  学习状态对象赋值给内部对象,也就是把stroe.js中的值,赋值给我们模板里data中的值。有三种赋值方式:

(1)通过computed的计算属性直接赋值

  computed属性可以在输出前,对data中的值进行改变,我们就利用这种特性把store.js中的state值赋值给我们模板中的data值。

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

  这里需要注意的是return this.$store.state.count这一句,一定要写this,要不你会找不到$store的。这种写法很好理解,但是写起来是比较麻烦的,那我们来看看第二种写法。

(2)通过mapState的对象来赋值

  我们首先要用import引入mapState。

import {mapState} from 'vuex';//然后还在computed计算属性里写如下代码:
computed:mapState({count:state=>state.count  //理解为传入state对象,修改为state.count属性
})

  这里我们使用ES6的箭头函数来给count赋值。

(3)通过mapState的数组来赋值

computed:mapState(["count"])

  这个算是最简单的写法了,在实际项目开发当中也经常这样使用

5、模板获取Mutations方法

  实际开发中我们也不喜欢看到$store.commit( )这样的方法出现,我们希望跟调用模板里的方法一样调用。 例如:@click=”reduce” 就和没引用vuex插件一样。要达到这种写法,只需要简单的两部就可以了:

//1、用import 引入我们的mapMutations:
import {mapGetters,mapMutations} from 'vuex'
//2、添加methods属性,并加入mapMutations
...mapMutations(['changeReportReview']),

  mapGetters、mapActions,都是一样的用法

methods:{...mapMutations([  'add','reduce']),...mapActions(['addAction','reduceAction'])
},

  需要注意的是,(1)调用的时候都是需要加上this才能访问到的;(2)getters/mutations/actions这些如果没带命名空间的话,就算是写在module模块里的这些方法,但是在使用的时候,是不需要加上模块名称的,而state是要加上模块名称的

二、状态管理模式

  “单向数据流”理念的极简示意:

  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

  我们在开发中会遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。

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

  对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件(非父子组件)间的状态传递无能为力;

  对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

三、Vuex简介

  Vuex 和单纯的全局对象有以下两点不同:

  • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  • 不能直接改变 store 中的状态改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vue.use(Vuex);
const store = new Vuex.Store({// 数据状态state {...},// 更改状态 store.commitmutations: {...},// 类似于mutation(不能直接变更状态,可以异步操作) store.dispatchactions: {...},// 派生状态(如,过滤、计数)getters: {...}
})// 将状态从根组件“注入”到每一个子组件中,且子组件能通过 this.$store 访问到。
const app = new Vue({el: '#app',store,data() {}
});
 

四、State

  Vuex 使用单一状态树,这可以让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。需要注意,单状态树和模块化并不冲突!

  由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。

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

  mapState 辅助函数

  当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性。

import { mapState } from 'vuex'computed: mapState({// 映射 this.count 为 store.state.count'count',// 箭头函数可使代码更简练count: state => state.count,// 传字符串参数 'count' 等同于 `state => state.count`countAlias: 'count',// 为了能够使用 `this` 获取局部状态,必须使用常规函数countPlusLocalState (state) {return state.count + this.localCount},// 使用对象展开运算符将此对象混入到外部对象中...mapState({// ...})
})
 

五、Getter

  Getter(state, getters)可以从 store 中的 state 中派生出一些状态(如,对数据进行过滤操作)。对于多个组件需要用同一属性时,意义重大!类似于计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

  完整请参照 https://vuex.vuejs.org/zh-cn/getters.html

六、Mutation

  mutation 必须是同步函数!!!

  更改 Vuex 的 store 中的状态的唯一方法是提交 mutation

  Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。调用 store.commit(type, payload) 方法来触发mutations中的相关方法。

mutations: {increment (state, n) {state.count += n}
}store.commit('increment', 10)
 

  注意:Mutation 需遵守 Vue 的响应规则

  • 最好提前在你的 store 中初始化好所有所需属性

  • 当需要在对象上添加新属性时,你应该

    • 使用 Vue.set(obj, 'newProp', 123), 或者

    • 以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写

state.obj = { ...state.obj, newProp: 123 }

  完整请参照:https://vuex.vuejs.org/zh-cn/mutations.html

七、Action

  Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
  • 通过 store.dispatch 方法触发

  组合 Action:store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise。

actions: {actionA ({ commit }) {return new Promise((resolve, reject) => {setTimeout(() => {commit('someMutation')resolve()}, 1000)})}
}
//现在你可以:
store.dispatch('actionA').then(() => {// ...
})

 

 

  在另外一个 action 中也可以:

// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {async actionA ({ commit }) {commit('gotData', await getData())},async actionB ({ dispatch, commit }) {await dispatch('actionA') // 等待 actionA 完成commit('gotOtherData', await getOtherData())}
}
 

  一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。

  完整请参照:https://vuex.vuejs.org/zh-cn/actions.html

八、Module

  由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)

  默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为命名空间模块当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

九、插件

  Vuex 的 store 接受 plugins 选项,这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数,它接收 store 作为唯一参数。

const myPlugin = store => {// 当 store 初始化后调用store.subscribe((mutation, state) => {// 每次 mutation 之后调用// mutation 的格式为 { type, payload }})
}
 

  然后像这样使用:

const store = new Vuex.Store({// ...plugins: [myPlugin]
})

  项目中我们会使用plugin来初始化一些数据

const initActionList = ['base/' + INIT_BUSINESS_SYSTEM_LIST,'threat/' + INIT_STD_COEFFICIENT_LIST
]
export default function (store) {for (let action of initActionList) {Bus.$once(action, () => {store.dispatch(action)})}
}
 

  但是 ,使用plugin的Bus.$once去初始化请求,而不再每个使用模块自身dispatch。会有解决不掉的两个问题:

  • 点击某个按钮触发相关数据($once只适合初始化时请求)
  • 某请求依赖store中的情况(刷新)await dispatch('actionA') // 等待 actionA 完成

十、表单处理

  当在严格模式中使用 Vuex 时,在属于 Vuex 的 state 上使用 v-model 会比较棘手

<input v-model="obj.message">

  在用户输入时,v-model 会试图直接修改 obj.message。在严格模式中,由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。使用传统的value+input事件实现,但是比较啰嗦。

<input :value="message" @input="updateMessage">computed: {...mapState({message: state => state.obj.message})
},
methods: {updateMessage (e) {this.$store.commit('updateMessage', e.target.value)}
}

  这里,可以使用双向绑定的计算属性

computed: {message: {get () {return this.$store.state.obj.message},set (value) {this.$store.commit('updateMessage', value)}}
}

  总结:使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac OS Git 安装

一、Git是一个分布式的代码版本管理工具。类似的常用工具还有SVN,CVS。最大的特点也是优点在于提供分布式的代码管理 1、分支代码只有一份&#xff01; 使用过svn的童鞋想必都知道&#xff0c;当我们要开发一个新功能或者增加一个新版本或者修改一个复杂bug的时候&#xff0c…

JS对象与jQuery对象

JS对象大致可以分为三种&#xff0c;如下图&#xff1a; JS常用内置对象&#xff08;JS自身所持有的对象&#xff0c;不需要创建&#xff0c;直接可用&#xff09;&#xff1a; String&#xff1a;API跟java的字符串API大致相同 两种创建对象的方式&#xff1a;String s1 “…

Nginx Slab内存管理

L38 Slub内存管理适用 ngx_http_limit_conn_module、ngx_http_limit_req_module 模块场景 我们可以用阿里第三方模块Slab_Stat模块 并且用add-module 方式编译进openresty中 转载于:https://www.cnblogs.com/jackey2015/p/10684151.html

Node.js异步库async

async的使用需要安装第三方包 1.串行无关联 async.series 函数依次执行,后面不需要调前面步骤的结果 程序执行时间为所有步骤之和 2.并行无关联 async.paraller 某步出错不影响其他步骤执行 程序执行时间为最长的那个时间 3.串行有关联 async.waterfall 函数依次执行,后面需要…

vue的双向绑定原理及实现

前言 使用vue也好有一段时间了&#xff0c;虽然对其双向绑定原理也有了解个大概&#xff0c;但也没好好探究下其原理实现&#xff0c;所以这次特意花了几晚时间查阅资料和阅读相关源码&#xff0c;自己也实现一个简单版vue的双向绑定版本&#xff0c;先上个成果图来吸引各位&a…

作业——8

这个作业属于哪个课程C语言程序设计Ⅱ这个作业的要求在哪里C语言作业评价标准我在这个课程的目标是指针与字符串这个作业在哪个具体方面帮助我实现目标使用指针与字符串参考文献指针和字符串&#xff08;基础知识&#xff09;第七周作业 一 1 、使用函数删除字符串中的字符 输入…

Vue实现组件props双向绑定解决方案

注意&#xff1a; 子组件不能直接修改prop过来的数据&#xff0c;会报错 方案一&#xff1a; 用data对象中创建一个props属性的副本 watch props属性 赋予data副本 来同步组件外对props的修改 watch data副本&#xff0c;emit一个函数 通知到组件外 HelloWorld组件代码如下…

Flask系列06--(中间件)Flask的特殊装饰器 before_request,after_request, errorhandler

一.使用 Flask中的特殊装饰器(中间件)方法常用的有三个 app.before_request # 在请求进入视图函数之前app.after_request # 在请求结束视图函数之后 响应返回客户端之前app.errorhandler(404) # 重定义错误信息before_request def func():passafter_request def func(ret): # …

CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

最近看了很多这方面的文章&#xff0c;能搜到的基本看了个遍&#xff0c;但感觉还是似懂非懂&#xff0c;知道这个东西&#xff0c;很难说出这是个什么东西&#xff0c;先整理一些概念&#xff0c;慢慢消化&#xff0c;以后慢慢探索其中的原因。 1、PX(CSS pixels) 1.1 定义 …

【转】10条你不可不知的css规则

10条你不可不知的css规则 Posted on 2006-12-20 10:33 雨中太阳 阅读(343) 评论(1) 编辑 收藏 &#xff1a;【译】10条你不可不知的css规则正文&#xff1a; Published December 6th, 2004 in CssStaff Tags: No Tags. 原文地址&#xff1a;Ten CSS Tricks You May not Know k…

Python 面向对象【1】

对象 属性 方法面向对象特征&#xff1a;分装 继承 多态【不同对象对同一方法响应不同行动】类定义class xxx:........类对象类对象支持两种操作&#xff1a;属性引用和实例化 属性引用 使用和 Python 中所有的属性引用一样的标准语法&#xff1a;类对象名.属性名 类对象创建…

福大软工 · 第八次作业(课堂实战)- 项目UML设计(团队)

1、队伍信息&#xff1a; 队伍名称&#xff1a;彳艮彳亍团队 学号名本次作业博客链接031602219奇豪(队长)https://www.cnblogs.com/S031602219/p/9822576.html041602209毓明http://www.cnblogs.com/mingsonic/p/9820702.html041602204水源http://www.cnblogs.com/littlenorthwe…

【转发】实现yolo3模型训练自己的数据集总结

原文链接&#xff1a;实现yolo3模型训练自己的数据集总结 经过两天的努力&#xff0c;借鉴网上众多博客&#xff0c;在自己电脑上实现了使用yolo3模型训练自己的数据集并进行测试图片。本文主要是我根据下面参考文章一步步实施过程的总结&#xff0c;可能没参考文章中那么详细&…

Django Form和ModelForm组件

Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时&#xff0c;都会写一些获取用户输入的标签并且用form标签把它们包起来。 与此同时我们在好多场景下都需要对用户的输入做校验&#xff0c;比如校验用户是否输入&#xff0c;输入的长度和格式等正不正确。如果用户输…

ESLint 规则详解

前端界大神 Nicholas C. Zakas 在 2013 年开发的 ESLint&#xff0c;极大地方便了大家对 Javascript 代码进行代码规范检查。这个工具包含了 200 多条 Javascript 编码规范且运行迅速&#xff0c;是几乎每个前端项目都必备的辅助工具。可是&#xff0c;这么多规则&#xff0c;每…

全文搜索引擎 ElasticSearch 还是 Solr?

原文链接 最近项目组安排了一个任务&#xff0c;项目中用到了全文搜索&#xff0c;基于全文搜索 Solr&#xff0c;但是该 Solr 搜索云项目不稳定&#xff0c;经常查询不出来数据&#xff0c;需要手动全量同步&#xff0c;而且是其他团队在维护&#xff0c;依赖性太强&#xff0…

NodeJS作为Web架构中间层的使用

截至2016年12月&#xff0c;中国网民规模已达7.31亿。传统的网站系统是否能够支撑得起如此庞大的且不断增长的用户访问并且为用户提供体验友好的页面&#xff1f; 一、传统的前后端&#xff1a; 二、传统的前后端分离问题&#xff1a; 性能问题&#xff1a; 1、渲染、数据都在…

windows server 2012 流媒体服务器搭建(直播与点播)

IIS Live Smooth Streaming&#xff08;实时平滑流式处理&#xff09;是微软下一代流媒体解决方案。该技术是在IIS web中集成媒体传输平台IIS media services&#xff0c;实现利用标准 HTTP Web 技术以及高级 Silverlight 功能&#xff0c;确保在互联上传输质量最佳、播放流畅音…

Vue warn Failed to mount component: template or render function not defined

问题如图&#xff0c;造成这类的问题一般有这么几个原因。 代码的拼写问题&#xff0c;当然这是最低级的错误vue定义的问题&#xff0c;这里我说明两点 在组件内部定义组件时&#xff0c;template 对应的必须是html字符串引用外部组件时&#xff0c;vue文件必须以template标签…

Python实现线性回归2,梯度下降算法

接上篇 4.梯度下降算法 《斯坦福大学公开课 &#xff1a;机器学习课程》吴恩达讲解第二课时&#xff0c;是直接从梯度下降开始讲解&#xff0c;最后采用向量和矩阵的方式推导了解析解&#xff0c;国内很多培训视频是先讲解析解后讲梯度下降&#xff0c;个人认为梯度下降算法更为…