javascriptvue.jsvuejs3vue-props

Reactive Prop Input Vue3


Explanation

I have a parent and a child component.

The child component is created using v-for='course in allCourses', cycling through an array of objects. It receives a bool called isSelected via props.

The isSelected bool depends on if the respective course of the child component is contained in another array: const selectedCourses = ref<Array<Object>>()

To check for this i implemented an arrow function that looks like this:

const isSelected = (_courseData :any) :boolean => {
    if (selectedCourses.value?.some(e => e == _courseData)) {
        return true
    }
    else {
        return false
    }
}

This i added into the prop of my child component as follows:

<mychildcomponent v-for="course in allCourses" :isSelected="isSelected(course)" @toggle-select="handleSelect"/>

Problem

However, of course, this does not update when there are changes made to the selectedCourses-Array, as i do via an emit in my child component.

When the child is clicked, it emits its data if its now selected or just false if it's now unselected. A simple function handles this inside my parent component to either push the data to selectedCourses or remove it.

Question

How do i get my isSelected-function to run (and therefore update the isSelected-prop of each child component) when this emit fires (or maybe with a hook for when selectedCourses is updated)? I know i could just pass in the whole selectedCourses as a prop into my child component and evaluate it's state in there, however i do not want to do this to ensure prop stability.


Solution

  • The solution goes into the direction of Dimavas proposal in his comment.

    I had to do a little more though to make it fit for my needs.

    @toggle-select="isSelected($event, true)" :isSelected='isSelected(course, false)'
    

    The components emit now executes isSelected(). The event contains the data of the emit, also i pass in true as a second argument.

    isSelected looks like this:

    const isSelected = (_courseData :any, _update: boolean) :boolean => {
        if(_update) {
            handleSelect(_courseData)
        }
        if (selectedCourses.value?.some((e: any) => e == _courseData)) {
    
            return true
        }
        else {
            return false
        }
    }
    

    The _update-Bool we passed in earlier is there to stop this solution from entering an infinite loop, as isSelected() is also called in the isSelected-prop of my component. There we pass in false to stop the recursion.