简体   繁体   中英

Vuejs emit from grandchild to basic parent

If I have component in nested component 3-4 levels and:

(1) wishes to send data from basic parent component to the final child I must send from each parent to each child props - its nice, but

(2) if I want to receive data in basic parent component from the final child I have to emit to each of the children and get what I gave in the int's parent until it come to the basic component - is not so cool.

That's how it works?

<component1 @change="change">
    <component2 :data="data" @change="change">
        <component3 :data="data" @change="change">
            <component4 :data="data">
            </compoent4>
        </compoent3>
    </compoent2>
</compoent1>

And in each child component I will have:

props: {data: {type: String}},
methods: {
    change: function () {
        this.$emit('change', this.data)
    }
}

And in base parent component I will have:

data() {
    data: 1
    }
},
methods: {
    change: function () {
        this.$emit('change', this.data)
    }
}

Or it is best to do with vuex?

The proper way to overcome this issue in Vue is to use EventBus.

create a new file, and name it eventBus.js and put the following inside

import Vue from 'vue'
export default new Vue()

Then, on the files you want to communicate from, import the file and use as the following

send event:

import EventBus from '../eventBus' 
EventBus.$emit('MESSAGE_NAME', payload)

receive event:

  import EventBus from '../eventBus' 
  EventBus.$on('DATA_PUBLISHED', (payload) => {
      this.updateData(payload)
   })

Vuex or an event bus may be overkill and it will break your top-down component architecture.

If you really need one way data flow with a trigger and a result passed down:

You could do it react style: pass the change function down as a prop (it has access to parent data via closure), simply call it in the child. You could even use provide/inject.

<component1 :change="change">
    <component2 :data="data" :change="change">
        <component3 :data="data" :change="change">
            <component4 :data="data" :change="change">
            </compoent4>
        </compoent3>
    </compoent2>
</compoent1>

Component 1

props: {data: {type: String}},
methods: {
    change: function () {
        this.$emit('change', this.data)
    }
}

Component 4

props: {data: {type: String}, change: Function},
methods: {
    // no methods required! just call: this.change();
}

If you really just want a deep two way binding:

Instead of passing data down as a string prop, you could pass an object containing data down (you could even use provide/inject to skip layers). Then you don't need a change function you can just manipulate the data directly. As always, you can use provide/inject to skip layers.

<component1 :data="data">
    <component2 :obj="obj">
        <component3 :obj="obj" >
            <component4 :obj="obj">
            </compoent4>
        </compoent3>
    </compoent2>
</compoent1>

Component 1

props: {data: {type: String}},
computed: {
    obj: function () {
        return {data: this.data};
    }
}

Component 4

props: {obj: {type: Object}},
methods: {
    change: function (newValue) {
        this.obj.data = newValue;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM