Search code examples
javascriptvue.jsvuejs3vue-composition-api

Using ref() not reacting to reassignments - composition API


Here is a simple carousel:

<template>
    <div ref="wrapperRef" class="js-carousel container">
        <div class="row">
            <slot></slot>
        </div>

        <div class="row">
            <template v-for="n in noOfSlides" :key="n">
                <span style="margin-right: 25px;" @click="console.log(n)">O</span>
            </template>
        </div>
    </div>

</template>

This works using Options API. The noOfSlides is properly getting changed and the for-loop re-renders after mounting

export default {
    name: 'carousel',
    data() {

        return {
            noOfSlides: 0
        }
    },
    mounted(){
        this.noOfSlides = this.$refs.wrapperRef.querySelectorAll('.js-carousel-item').length;
    }
}

It doesn't work while using composition API like below. The noOfSlides is not getting changed and thus for-loop not re-rendering

export default {
    name: 'carousel',
    setup() {
        const wrapperRef = ref(null);
        let noOfSlides = ref(0);



        onMounted(function () {
            noOfSlides = wrapperRef.value.querySelectorAll('.js-carousel-item').length;// this here properly returning the number of slides(more than 0 anyway)
        })

        return {
            wrapperRef,
            noOfSlides
        }
    }
}

What do I miss here?


Solution

  • This is not the Vue way to work with DOM, you could use slots :

    export default {
      name: 'carousel',
      setup(props, { slots }) {
        const wrapperRef = ref(null);
        let noOfSlides = ref(0);
    
        onMounted(function () {
          console.log('slots ', slots.default());
          noOfSlides.value = slots.default().length;
        });
        function log(n) {
          console.log('n ', n);
        }
        return {
          wrapperRef,
          noOfSlides,
          log,
        };
      },
    };
    

    DEMO