From 3507eb8ea36e87b87c474ebd61d03c4449dcc71d Mon Sep 17 00:00:00 2001 From: kingwl <805037171@163.com> Date: Mon, 20 Mar 2017 13:44:27 +0800 Subject: [PATCH 1/2] fix provide isn't reactive with a single array - Fix #5223 --- src/core/instance/inject.js | 3 +- test/unit/features/options/inject.spec.js | 34 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/core/instance/inject.js b/src/core/instance/inject.js index 0b1a071e3c4..89a98ab49fb 100644 --- a/src/core/instance/inject.js +++ b/src/core/instance/inject.js @@ -1,6 +1,7 @@ /* @flow */ import { hasSymbol } from 'core/util/env' +import { defineReactive } from '../observer/index' export function initProvide (vm: Component) { const provide = vm.$options.provide @@ -29,7 +30,7 @@ export function initInjections (vm: Component) { let source = vm while (source) { if (source._provided && provideKey in source._provided) { - vm[key] = source._provided[provideKey] + defineReactive(vm, key, source._provided[provideKey]) break } source = source.$parent diff --git a/test/unit/features/options/inject.spec.js b/test/unit/features/options/inject.spec.js index ac67749f43d..86c03717e30 100644 --- a/test/unit/features/options/inject.spec.js +++ b/test/unit/features/options/inject.spec.js @@ -162,4 +162,38 @@ describe('Options provide/inject', () => { expect(vm.$el.textContent).toBe('123') }) } + + // Github issue #5223 + it('should work with reactive array', done => { + const vm = new Vue({ + template: `
`, + data () { + return { + foo: [] + } + }, + provide () { + return { + foo: this.foo + } + }, + components: { + child: { + inject: ['foo'], + template: `{{foo.length}}` + } + } + }).$mount() + + expect(vm.$el.innerHTML).toEqual(`0`) + vm.foo.push(vm.foo.length) + vm.$nextTick(() => { + expect(vm.$el.innerHTML).toEqual(`1`) + vm.foo.pop() + vm.$nextTick(() => { + expect(vm.$el.innerHTML).toEqual(`0`) + done() + }) + }) + }) }) From 4a5733ca915cd3d643202ba8506c74cee8b2b63b Mon Sep 17 00:00:00 2001 From: kingwl <805037171@163.com> Date: Tue, 21 Mar 2017 12:35:35 +0800 Subject: [PATCH 2/2] add warning when injections has been modified --- src/core/instance/inject.js | 14 +++++++++++++- test/unit/features/options/inject.spec.js | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/core/instance/inject.js b/src/core/instance/inject.js index 89a98ab49fb..a2954163140 100644 --- a/src/core/instance/inject.js +++ b/src/core/instance/inject.js @@ -1,6 +1,7 @@ /* @flow */ import { hasSymbol } from 'core/util/env' +import { warn } from '../util/index' import { defineReactive } from '../observer/index' export function initProvide (vm: Component) { @@ -30,7 +31,18 @@ export function initInjections (vm: Component) { let source = vm while (source) { if (source._provided && provideKey in source._provided) { - defineReactive(vm, key, source._provided[provideKey]) + if (process.env.NODE_ENV !== 'production') { + defineReactive(vm, key, source._provided[provideKey], () => { + warn( + `Avoid mutating a injections directly since the value will be ` + + `overwritten whenever the provided component re-renders. ` + + `injections being mutated: "${key}"`, + vm + ) + }) + } else { + defineReactive(vm, key, source._provided[provideKey]) + } break } source = source.$parent diff --git a/test/unit/features/options/inject.spec.js b/test/unit/features/options/inject.spec.js index 86c03717e30..bfb5e5bd143 100644 --- a/test/unit/features/options/inject.spec.js +++ b/test/unit/features/options/inject.spec.js @@ -196,4 +196,25 @@ describe('Options provide/inject', () => { }) }) }) + + it('should warn when injections has been modified', () => { + const key = 'foo' + const vm = new Vue({ + provide: { + foo: 1 + } + }) + + const child = new Vue({ + parent: vm, + inject: ['foo'] + }) + + expect(child.foo).toBe(1) + child.foo = 2 + expect( + `Avoid mutating a injections directly since the value will be ` + + `overwritten whenever the provided component re-renders. ` + + `injections being mutated: "${key}"`).toHaveBeenWarned() + }) })