简体   繁体   中英

What's the right approach to update a parent's component array of objects from a child component?

I have a complex form with different tabs. I use vue-router to switch between these and display different modular components in a router-view for each one of them. In these tabs I have child components with sometimes other nested child components. I use the event bus approach to pass data from these child components up in tree. I'm doing this because the final tab will be a summary of the form, and I will need access to all the form data. At the moment I'm using something like the below.

For example using this structure:

|App
--|Start
--|Question 1
  --|Answer 1
  --|Answer 2
--|Question 2
...

In the root component (App):

data() {
  return {
    questions: 0,
    answers: []
  }
},
created() {
    eventBus.$on('answer-added', answer => {
        let answer_exists = false
        this.answers.forEach( (e, i) => {
            if(e.id == answer.answer_id) answer_exists = true
        });
        if(!answer_exists) this.answers.push({
            id: answer.answer_id,
            answer: answer.answer_text
        })
    });
}

What's the proper way to create/update/delete the array of answers in the App component every time an event from the child is fired? I'm sure there must be a much better way than iterating over the array elements to check whether the answer already existed or not... Just can't figure it out.

Do you mean something like:

if (!this.answers.find(a => a.id === answer.answer_id)) {
    this.answers.push(/* ... */);
}

What you are doing is more or less right. There is no escape from the loop. However, there are certain things you can improve upon. Instead of forEach , you can use Array.some method . Alternately, you can use Array.find method:

eventBus.$on('answer-added', answer => {

    // Instead of using forEach, you can use Array.some() method
    const answerExists = this.answers.some((x) => e.id == answer.answer_id);

    if (!answerExists) {
      this.answers.push({
        id: answer.answer_id,
        answer: answer.answer_text
      });
    }
});

Second, there is no problem with using an event bus , but it is generally used for a sibling or cross-component communication. When all the components are in the same ancestor or parent hierarchy, using $emit for events is the right way.

In your case, even though you have a nested components hierarchy, as the application evolves, a hierarchy can get really deep and you will quickly lose the track of typical publish-subscribe mechanism of the event bus. Even if it means re-emitting the same events from intermediate components, you should follow this practice.

For anyone who comes across with the same issue, the problem I encountered is resolved by using a Simple Global Store . Other more complex scenarios would possibly require Vuex as suggested by @Dan above.

Pass a callback from parent to child. Now they can communicate bottom up. The child can pass any data the parent might want and then the parent can take back control and use its state or closure state.

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