6

vue 无法监听实例内部修改的变化

 2 years ago
source link: https://www.v2ex.com/t/845573
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  程序员

vue 无法监听实例内部修改的变化

  zhaojingfeng · 2 小时 26 分钟前 · 291 次点击
const form = reactive(new T_RAGENCY())
export class T_RAGENCY {
 ID:number
 updateID = () => {
	this.ID++
 }
}
form.updateID()

watchEffect 或 watch 无法监听到变化. 页面中双向绑定的值也无法变化.

10 条回复    2022-04-07 22:58:33 +08:00

zhaojingfeng

zhaojingfeng      2 小时 16 分钟前

有大佬知道怎么解决么

noe132

noe132      2 小时 10 分钟前

你试试在 updateID 把 "this" log 出来看看是什么?

ymcz852

ymcz852      2 小时 8 分钟前

我猜测是 reactive 返回了一个 T_RAGENCY 实例的代理 proxy 对象(响应式副本),实际上监听的是 proxy 对象 form.updateID() 更新的是原始实例的值,proxy 对象监听不到

noe132

noe132      2 小时 1 分钟前

@ymcz852 你仔细看看代码,updateID 的 this 到底是什么

Kawa

Kawa      1 小时 53 分钟前

不知道你有没有了解过 Proxy 和 Vue toRaw 的原理.
简单的用例大概是这样的:
const ProxyObj = Proxy(obj, {
get(target, property) {
console.log("read: "property);
return target[property];
},
set(target, property, value) {
console.log("write: "property);
target[property] = value;
}
});
Vue 的 reactive 基本实现原理就是 Proxy.
想象上面 Proxy 的用例, 如果直接对 obj 写入, 那显然不会触发 Proxy 里的 set handler.
如果对 ProxyObj 写入, 那么就会触发 set handler.
同样的道理, 如果你想触发 reactive 的更新, 那么你就需要对 reactive 包裹过的对象执行写入, 而不是对原对象.

而且我认为 reactive 应该仅存数据, 而不应该包括方法.

Kawa

Kawa      1 小时 48 分钟前

当然, 如果你非要这样做, 也是有办法的.
比较简单的方法就是做一个 factory, 通过 factory 创建裸对象, 再将其用 reactive 包裹, 最后向其注入 mutation 方法.
非要 new 也不是不行, 可以在类的内部自行维护一个 reactive 对象, 然后定义类属性的 getter 和 setter, 将操作映射到 reactive 对象上.

nomagick

nomagick      1 小时 40 分钟前

assert(this instanceof T_RAGENCY)

括号函数 this 是在构造的时候决定的,但 vue 拿到你这个对象之后是把上面的属性和方法拿走,舍弃了最初的实例。
之前 vue 就有这个问题,没有维护原型链

noe132

noe132      1 小时 30 分钟前

@ymcz852 用了这么久 JS ,我居然把这个搞错了~

这个问题我终于搞明白了。因为 class field 用的是 [[Define]] ( https://github.com/tc39/proposal-class-fields)
class { updateId = () => console.log(this) }
相当于
class {
constructor(){
Object.defineProperty(this, 'updateId', { value: () => console.log(this), enumerable: true, configurable: true, writable: true });
}
}

此时这个方法相当于是在构造函数内定义的,箭头函数内的 this 绑定成了构造函数执行时的 this 。
当 class instance 被 proxy 包了一层后,调用 updateId 拿到的 this 是原对象而不是 proxy ,导致更新没法被检测到。

如果把方法定义成 class method ,this 就是 proxy 。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK