Search code examples
vue.jsrenderviewmodeltrackingchildren

Tracking a child state change in Vue.js


I have a component whose purpose is to display a list of items and let the user select one or more of the items.

This component is populated from a backend API and fed by a parent component with props.

However, since the data passed from the prop doesn't have the format I want, I need to transform it and provide a viewmodel with a computed property.

I'm able to render the list and handle selections by using v-on:click, but when I set selected=true the list is not updated to reflect the change in state of the child.

I assume this is because children property changes are not tracked by Vue.js and I probably need to use a watcher or something, but this doesn't seem right. It seems too cumbersome for a trivial operation so I must assume I'm missing something.

Here's the full repro: https://codesandbox.io/s/1q17yo446q

By clicking on Plan 1 or Plan 2 you will see it being selected in the console, but it won't reflect in the rendered list.

Any suggestions?


Solution

  • In your example, vm is a computed property.

    If you want it to be reactive, you you have to declare it upfront, empty.
    Read more here: reactivity in depth.

    Here's your example working.

    Alternatively, if your member is coming from parent component, through propsData (i.e.: :member="member"), you want to move the mapper from beforeMount in a watch on member. For example:

    propsData: {
      member: {
        type: Object,
        default: null
      }
    },
    data: () => ({ vm: {}}),
    watch: {
      member: {
        handler(m) {
          if (!m) { this.vm = {}; } else {
            this.vm = {
              memberName: m.name,
              subscriptions: m.subscriptions.map(s => ({ ...s }))
            };
          }
        },
        immediate: true
      }
    }