Browse Source

fix provide isn't reactive with a single array (#5229)

* fix provide isn't reactive with a single array - Fix #5223

* add warning when injections has been modified
dev
kingwl 8 years ago
committed by Evan You
parent
commit
7dea9f1eb2
  1. 15
      src/core/instance/inject.js
  2. 55
      test/unit/features/options/inject.spec.js

15
src/core/instance/inject.js

@ -1,6 +1,8 @@
/* @flow */
import { hasSymbol } from 'core/util/env'
import { warn } from '../util/index'
import { defineReactive } from '../observer/index'
export function initProvide (vm: Component) {
const provide = vm.$options.provide
@ -29,7 +31,18 @@ export function initInjections (vm: Component) {
let source = vm
while (source) {
if (source._provided && provideKey in source._provided) {
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

55
test/unit/features/options/inject.spec.js

@ -162,4 +162,59 @@ 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: `<div><child></child></div>`,
data () {
return {
foo: []
}
},
provide () {
return {
foo: this.foo
}
},
components: {
child: {
inject: ['foo'],
template: `<span>{{foo.length}}</span>`
}
}
}).$mount()
expect(vm.$el.innerHTML).toEqual(`<span>0</span>`)
vm.foo.push(vm.foo.length)
vm.$nextTick(() => {
expect(vm.$el.innerHTML).toEqual(`<span>1</span>`)
vm.foo.pop()
vm.$nextTick(() => {
expect(vm.$el.innerHTML).toEqual(`<span>0</span>`)
done()
})
})
})
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()
})
})

Loading…
Cancel
Save