vue实例data数据中对象属性里未定义的字段在模板里使用并改变,会被监听到,但是js使用就监听不到。

Created on 16 Jan 2020  ·  3Comments  ·  Source: vuejs/vue

Version

2.6.11

Reproduction link

https://codepen.io/Jason6385/pen/xxbaVJB?editors=1111

Steps to reproduce

1、进入页面,先在输入框里输入内容,输入框下面会动态更新值,console里也会打印监听内容,再点击按钮改变变量值也能监听到。
2、进入页面,先点击按钮改变同一个变量,监听不到改变,再在输入框里输入内容也监听不到。
3、将created中的注释代码打开,进入页面重复1和2操作,变量改变都监听不到。

What is expected?

第1步应该也是监听不到

What is actually happening?

第1步能监听到

Most helpful comment

@Jason2048
use english describle issue may be better!
if you want to know what cause this situation, i recommend you read source code: src/directives/model.js
you should konw the user.age is not reactively, because it not define in the data
for step 1: when you input before click, trigger the v-model directives, becuase age is not in targer object user, v-model directive will help you set your user.age to reactively, see this code$set(${res.exp}, ${res.key}, ${assignment}):

export function genAssignmentCode (
  value: string,
  assignment: string
): string {
  const res = parseModel(value)
  if (res.key === null) {
    return `${value}=${assignment}`
  } else {
    return `$set(${res.exp}, ${res.key}, ${assignment})`
  }
}
function set (target, key, val) {
    if (isUndef(target) || isPrimitive(target)
    ) {
      warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
    }
    if (Array.isArray(target) && isValidArrayIndex(key)) {
      target.length = Math.max(target.length, key);
      target.splice(key, 1, val);
      return val
    }
    if (key in target && !(key in Object.prototype)) {
      target[key] = val;
      return val
    }
    var ob = (target).__ob__;
    if (target._isVue || (ob && ob.vmCount)) {
      warn(
        'Avoid adding reactive properties to a Vue instance or its root $data ' +
        'at runtime - declare it upfront in the data option.'
      );
      return val
    }
    if (!ob) {
      target[key] = val;
      return val
    }
    defineReactive$$1(ob.value, key, val);
    ob.dep.notify();
    return val
  }

for step2: if you click before input, you have defined age in target obj user, so this code defineReactive$$1(ob.value, key, val);will not run. the age is not reactively

for step3: same reason as step 2

All 3 comments

@Jason2048
use english describle issue may be better!
if you want to know what cause this situation, i recommend you read source code: src/directives/model.js
you should konw the user.age is not reactively, because it not define in the data
for step 1: when you input before click, trigger the v-model directives, becuase age is not in targer object user, v-model directive will help you set your user.age to reactively, see this code$set(${res.exp}, ${res.key}, ${assignment}):

export function genAssignmentCode (
  value: string,
  assignment: string
): string {
  const res = parseModel(value)
  if (res.key === null) {
    return `${value}=${assignment}`
  } else {
    return `$set(${res.exp}, ${res.key}, ${assignment})`
  }
}
function set (target, key, val) {
    if (isUndef(target) || isPrimitive(target)
    ) {
      warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
    }
    if (Array.isArray(target) && isValidArrayIndex(key)) {
      target.length = Math.max(target.length, key);
      target.splice(key, 1, val);
      return val
    }
    if (key in target && !(key in Object.prototype)) {
      target[key] = val;
      return val
    }
    var ob = (target).__ob__;
    if (target._isVue || (ob && ob.vmCount)) {
      warn(
        'Avoid adding reactive properties to a Vue instance or its root $data ' +
        'at runtime - declare it upfront in the data option.'
      );
      return val
    }
    if (!ob) {
      target[key] = val;
      return val
    }
    defineReactive$$1(ob.value, key, val);
    ob.dep.notify();
    return val
  }

for step2: if you click before input, you have defined age in target obj user, so this code defineReactive$$1(ob.value, key, val);will not run. the age is not reactively

for step3: same reason as step 2

Things are working fine in this case. When adding properties to an object, you must use Vue.set() or $this.set


Remember you can use the forum or the Discord chat to ask quick questions!

@Jason2048
https://cn.vuejs.org/v2/guide/reactivity.html#%E6%A3%80%E6%B5%8B%E5%8F%98%E5%8C%96%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bdedardel picture bdedardel  ·  3Comments

franciscolourenco picture franciscolourenco  ·  3Comments

wufeng87 picture wufeng87  ·  3Comments

fergaldoyle picture fergaldoyle  ·  3Comments

loki0609 picture loki0609  ·  3Comments