1

Given that a colon indicates one-way-data-binding in VueJS2, I would like to understand why in this example, the child is able to update the array that was declared in the parent and passed to the child via prop (one-way).

https://jsfiddle.net/ecgxykrt/

<script src="https://unpkg.com/vue"></script>

<div id="app">
    <span>Parent value: {{ dataTest }}</span>
    <test :datatest="dataTest" />
</div>

var test = {
    props: ['datatest'],
    mounted: function() {
        this.datatest.push(10)
    },
    render: function() {}
}

new Vue({
    el: '#app',
    components: {
        'test': test
    },
    data: function() {
        return {
            dataTest: []
        }
    }
})

Thanks in advance!

  • I am pretty interested in the answer since the answers thus fair do nothing to explain this. And vue explicitly state that this is a one way binding and you should even get a warning when mutating a prop directly. – Stephan-v Sep 12 '17 at 15:00
  • 1
    @Stephan-v Objects and arrays are passed by reference. You can modify them just like you can modify a `const` value. What you *cannot* do is change the prop to a completely new object or array. – Bert Sep 12 '17 at 15:13

3 Answers3

1

Vue prevents you from assigning to a prop. It does not prevent you from calling a prop's methods or modifying its elements or members, any of which can change the contents of the object. None of these things changes the value of the prop itself, which is a reference to an underlying structure.

A related issue is the fact that Vue cannot detect changes to Array elements or additions/deletions of Object members.

More here.

tony19
  • 125,647
  • 18
  • 229
  • 307
Roy J
  • 42,522
  • 10
  • 78
  • 102
  • How does this explain why the child is able to update the parent data though? – Stephan-v Sep 12 '17 at 14:50
  • These caveats are also something entirely different since the length itself is not modified directly AND the item has already been set in advance. According to this a `push` should also be tracked properly. https://vuejs.org/v2/guide/list.html#Mutation-Methods – Stephan-v Sep 12 '17 at 14:59
  • The child gets a reference to the array and is therefore able to modify its contents. This is exactly the same circumstance that leads to the caveats. It has nothing to do with modifying the length, nor with the fact that the item is created in advance. The central issue is that an Object is a reference. – Roy J Sep 12 '17 at 15:13
  • So, since I change a property of a child injected prop object the parent is updated, this behavior breaks the "one-way" binding, right? What do I need to do to avoid this? Create a deep copy of every prop that is an object or array? – BR.A Design Studio Sep 12 '17 at 16:45
  • If you want a local data item to modify, yes, make a deep copy. Then work with the data item. Proper handling depends on what you are trying to accomplish. I would not say make a deep copy of every prop; there are lots of cases where you don't need to modify things. – Roy J Sep 12 '17 at 16:55
0

If you wanted to, you could avoid this by creating a shallow copy and assigning it to a new data item in the child.

https://jsfiddle.net/6xxba1fz/

var test = {
  props: ['test'],
  data: function() {
  return {
    myTest: this.test.slice()
  }
  },
  mounted: function() {
    this.myTest.push(10)
  },
  render: function() {}
}

new Vue({
  el: '#app',
  components: {
    'test': test
  },
  data: function() {
    return {
      dataTest: []
    }
  }
})
Brian Glaz
  • 15,468
  • 4
  • 37
  • 55
-2

Please avoid to using the some name for key and value

:datatest="dataTest" Wrong Way

:data-test="dataTest" Better Way (use Kabab case)

HTML

<div id="app">
  <span>Parent value: {{ dataTest }}</span>
  <test :data-test="dataTest" />
</div>

JS

var test = {
  props: {
        dataTest:{
        type:Number
      }
  },
  mounted: function() {
    this.datatest.push(10)
  },
  render: function() {}
}

new Vue({
  el: '#app',
  components: {
    'test': test
  },
  data: function() {
    return {
      dataTest: []
    }
  }
})

Result:

Parent value: []

Community
  • 1
  • 1
Omri Lugasi
  • 337
  • 3
  • 16
  • You are pushing to `datatest` instead of `dataTest` though. If you check your console this will lead to an error and you will of course keep the empty array. – Stephan-v Sep 12 '17 at 14:55
  • This answer should just be a comment in the OP. – Kalnode Dec 14 '19 at 13:41