【踩坑记录】Vuex中更改state的数据但是Vue中没有做出改变

3,817 阅读2分钟

今天在做Vue开发的时候遇到了个很奇怪的现象:改变了Vuex中的state的数据,但是页面没有做出改变。

首先放出代码:

Vuex:

import {
	createStore
} from 'vuex';

/**
 * 用户构造函数
 * @param {*} name 用户名
 */
function User(name) {
	this.name = name;
	/**
	 * 修改用户名
	 * @param {String} changedName 修改后用户名
	 */
	this.changeName = (changedName) => {
		this.name = changedName;
	}
}

export default createStore({
	state: {
		user: new User('swsk33')
	},
	mutations: {
		change(state) {
			state.user.changeName('swsk');
			console.log(state.user.name);
		}
	},
	actions: {
		change(context) {
			context.commit('change');
		}
	},
});

Vue组件:

<template>
	<div id="app">
		<div>{{ user.name }}</div>
		<div @click="change">更改</div>
	</div>
</template>

<script>
import { mapState, mapActions } from 'vuex';

export default {
	computed: {
		...mapState(['user']),
	},
	methods: {
		...mapActions(['change']),
	},
};
</script>

可见,在Vuex中,方便起见我定义了个构造函数,用于创建用户对象。可以看到,用户对象中有一个changeName函数可以更改自己的用户名,这个函数相当于可以更改自己的值。

然后在state中初始化一个用户对象,并定义好mutationsactions函数以测试更改,注意mutations中方法是使用用户对象自己的方法修改用户名,而不是直接赋值。

最后,vue组件中,映射Vuex中的userchange函数进行测试。理论上,我点击更改时,显示的用户名会变,然而点击后并没有变。

点击后网页:

image.png

网页上内容并没有变。

但是在控制台中输出这个state中的user,实质上已经改变了:

image.png

我们知道,state中的数据也是响应式的,而更改其数据的唯一方法就是mutations

但是可见,上述修改数据的形式并不同于平时,没有在mutations进行直接赋值,而是使用对象自己的方法修改自己。

这就是问题所在:mutations中的函数没有进行一个直接的更改对象的操作,而是间接地调用对象自己的方法修改对象自己。

这样,数据确实修改了,但是可以理解为:并非是mutations进行修改的。

这种情况下,mutations没有直接修改数据,就导致Vue中无法侦测到数据变化做出响应。

解决办法很简单,不要在构造函数中定义修改对象自己属性的方法,而是使用mutations修改即可。

我们修改上述Vuex如下:

import {
	createStore
} from 'vuex';

/**
 * 用户构造函数
 * @param {*} name 用户名
 */
function User(name) {
	this.name = name;
}

export default createStore({
	state: {
		user: new User('swsk33')
	},
	mutations: {
		changeName(state) {
			// 进行直接修改操作
			state.user.name = 'swsk';
		}
	},
	actions: {
		change(context) {
			context.commit('changeName');
		}
	},
});

所以,使用Vuex时,一定要牢记官方文档的这一句话:更改Vuex的store中的状态的唯一方法是提交mutation。

任何修改数据的操作应当放在mutations中,而非别的函数里面。