在楼主的一个自动化测试项目中,由于UI用例运行时间较长,要允许别人暂时去别的页面做别的事情,然后返回时可以看到运行结果。要实现这个功能,就需要保存当前页面数据,以便路由回来时还能获取上次的数据。因此必须将原来单文件组件中的data数据移至vuex中的store里面去保存。
在做完更改后,发现部分数据丢失,并没有恢复。通过vue-devtool查看state数据,发现出现了两个targetKeys属性,后来对比发现,原来其中一个叫targetKyes!这个属性是哪里来的?我的store模块定义如下:
/**
* 运行UI用例管理
* */
import * as mutations from './mutations';
import * as actions from './actions';
const runUiCases = {
state: { // state数据
selectGroup:[],//下拉框选择的用例组
targetKeys:[],// 待跑用例id列表
isRunning: false,//保存用例是否在运行状态,用于长时间运行时,可以自由跳转到别的页面先做别的事,然后返回时判断用例是否允许完毕
groupList: [], //功能点列表
casesList: [], // 用例列表
reporter: {
totalTime: 0,
count: 0,
passCount: 0,
allPass: true,
messageList: []
} //结果
},
mutations,
actions
};
export default runUiCases;
很明显,只有一个targetKeys属性,并且按照一般的经验,属性一般都是要提前定义好的,不允许中途加属性。后来想到能操纵state的只有mutation,翻到mutation一看,果然:
// 更新待跑用例keys
export const SET_TARGET_KEYS = (state, payload) => {// mutation第一个参数是state对象,第二个参数是传进来的额外参数
state.targetKyes = payload;
};
这里由于拼写错误,为state添加了一个新的属性!数据都保存到新属性里面去了,因此就出现了部分数据恢复不了的现象。
坑!怎么能如此轻易的就可以改变state的数据?
特地去查了下官网,官网的描述如下:
Mutation 需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
-
最好提前在你的 store 中初始化好所有所需属性。
-
当需要在对象上添加新属性时,你应该
-
使用
Vue.set(obj, 'newProp', 123)
, 或者 -
以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
说说我的看法。第1点很好理解,这样做state有哪些属性可以一目了然。可是!第2点,需要添加新属性的时候使用Vue.set()还能说得过去,你直接新对象替换老对象也行?Excuse Me?这不是在埋坑吗?到时候操作属性的时候,A发现state没有这个属性,通过新对象替换老对象,添加了属性。但其实这个属性B已经用同样的方式添加过了,而且类型不是A想要的那种。又或者,A想查看state有没有某个属性,他看了一眼state,没有,却不敢直接说没有,因为可能别的地方加了。
因此,上述规则的第2点,我认为不可取。后面出现新属性,完全可以直接添加到state中去即可。如果你太懒,铁了心要用第2种,我觉得使用Vue.set()也要比直接替换好很多!而且最好新属性通过常量定义好,这样查询state有哪些属性的时候,就可以从state和常量两个地方查就够了。但与其这么麻烦,为什么不直接添加呢?
回到我遇到的这个坑,如果mutation有限制,不能直接增删属性,必须通过类似mutation本身这样机制,那这个问题就可以避免或者说提前暴露出来。