{"record":{"id":"98786fcd3baf5406","repo":"Meituan-Dianping/mpvue","slug":"avoid-replacing-instance-root-data-use-nested-da","errorCode":null,"errorMessage":"Avoid replacing instance root $data. Use nested data properties instead.","messagePattern":"Avoid replacing instance root \\$data\\. Use nested data properties instead\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/weex-vue-framework/factory.js","lineNumber":3308,"sourceCode":"    handler = handler.handler;\n  }\n  if (typeof handler === 'string') {\n    handler = vm[handler];\n  }\n  return vm.$watch(keyOrFn, handler, options)\n}\n\nfunction stateMixin (Vue) {\n  // flow somehow has problems with directly declared definition object\n  // when using Object.defineProperty, so we have to procedurally build up\n  // the object here.\n  var dataDef = {};\n  dataDef.get = function () { return this._data };\n  var propsDef = {};\n  propsDef.get = function () { return this._props };\n  if (process.env.NODE_ENV !== 'production') {\n    dataDef.set = function (newData) {\n      warn(\n        'Avoid replacing instance root $data. ' +\n        'Use nested data properties instead.',\n        this\n      );\n    };\n    propsDef.set = function () {\n      warn(\"$props is readonly.\", this);\n    };\n  }\n  Object.defineProperty(Vue.prototype, '$data', dataDef);\n  Object.defineProperty(Vue.prototype, '$props', propsDef);\n\n  Vue.prototype.$set = set;\n  Vue.prototype.$delete = del;\n\n  Vue.prototype.$watch = function (\n    expOrFn,\n    cb,","sourceCodeStart":3290,"sourceCodeEnd":3326,"githubUrl":"https://github.com/Meituan-Dianping/mpvue/blob/6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b/packages/weex-vue-framework/factory.js#L3290-L3326","documentation":"In development builds, the $data and $props instance accessors are defined with getters only plus a setter that warns. Assigning vm.$data = {...} is rejected (the getter value is unchanged) because replacing the root reactive data object would break reactivity and proxies.","triggerScenarios":"Writing vm.$data = newObj or Object.assign used via direct replacement like this.$data = initialState() in a component, typically to 'reset' state.","commonSituations":"Trying to reset component state to initial values, copying state between components, or migration code that swapped whole data objects after Vue 1's looser behavior.","solutions":["Mutate properties on $data instead: Object.keys(newData).forEach(k => this[k] = newData[k])","Reset individual top-level keys to their initial values","Use a factory that returns initial state and assign key-by-key","Replace the component (v-if / :key) to get fresh state"],"exampleFix":"// before\nresetState() { this.$data = initialState(); }\n// after\nresetState() {\n  const fresh = initialState();\n  Object.keys(fresh).forEach(k => { this.$data[k] = fresh[k]; });\n}","handlingStrategy":"validation","validationCode":"function resetData(vm, initialFactory) {\n  const fresh = initialFactory();\n  Object.keys(fresh).forEach(k => { vm.$data[k] = fresh[k]; });\n}","typeGuard":"function isRootDataReplacement(stmt) {\n  return /\\$data\\s*=/.test(stmt);\n}","tryCatchPattern":null,"preventionTips":["Never assign to this.$data or this.$props directly","Reset state by reassigning individual keys","Use :key changes or v-if to remount a component for a full state reset"],"tags":["vue","data","reactivity","state-reset"],"backgroundTag":"root-data-replacement","analyzedSha":"6c5d78ee04f58c6d782c456dfcf0fe63c0b7f89b","analyzedAt":"2026-09-02T05:17:40.946Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T11:17:12.671Z"}