Home > front end >  VUE 3 Pass prop to watch composition API
VUE 3 Pass prop to watch composition API

Time:10-06

I am struggling with the Vue 3 Composition API. I am trying to split my code by logical concerns, and I can not figure out how to pass a property to be watched in a composable function.

This is the component:

export default defineComponent({
  props: {
    collapseY: {
      type: Boolean,
      required: false,
      default: false
    },
    barcodePulse: {
      type: Boolean,
      required: false,
      default: false
    }
  },
  setup(props) {
    const pulse = ref(props.barcodePulse)
    const {getRandomVerticalScaleValue, getRandomAnimationDuration} = usePulse(pulse)

    return {
      getRandomVerticalScaleValue,
      getRandomAnimationDuration
    }
  }
})

And this is the usePulse composable function:

export interface usePulseData {
    getRandomVerticalScaleValue: () => number;
    getRandomAnimationDuration: () => number;
}

export const usePulse: (pulse: Ref<boolean>) => usePulseData = (pulse) => {
    const stopBarcodeAniation = (event: Event) => {
        (event.target as Element).classList.remove('MY:brand-logo:bar-code:pulse');
        (event.target as Element).removeEventListener('animationiteration', stopBarcodeAniation);
    }

    watch(pulse, (value) => {
        console.log("Prop change")
        const rectangles = document.querySelectorAll('.MY\\:brand-logo\\:bar-code\\:rectangle')
        if (value) {
            for (let index = 0; index < rectangles.length;   index) {
                rectangles[index].classList.add('MY:brand-logo:bar-code:pulse')
            }
        } else {
            for (let index = 0; index < rectangles.length;   index) {
                rectangles[index].addEventListener('animationiteration', stopBarcodeAniation)
            }
        }
    })

    const getRandomVerticalScaleValue: () => number = () => {
        return (Math.floor(Math.random() * (10 - 4   1)   4) * 0.1) - 0.1;
    }

    const getRandomAnimationDuration: () => number = () => {
        return Math.floor(Math.random() * (20 - 10   1)   10) * 0.15
    }


    onMounted(() => {
        const rectangles = document.querySelectorAll('.MY\\:brand-logo\\:bar-code\\:rectangle')
        for (let index = 0; index < rectangles.length;   index) {
            (rectangles[index] as HTMLElement).style.setProperty('--animation-duration', `${getRandomAnimationDuration()}s`);
            (rectangles[index] as HTMLElement).style.setProperty('--scale-factor', `${getRandomVerticalScaleValue()}`);
        }
    })

    return {
        getRandomVerticalScaleValue,
        getRandomAnimationDuration
    } as usePulseData
}

The console.log('Prop changed') in the second code fragment for some reason doesn't execute.

Can any of you explain why this is not happening?

CodePudding user response:

The problem is in the following code:

const pulse = ref(props.barcodePulse) // ❌ loses props reactivity

usePulse(pulse)

props is a reactive object, but props.barcodePulse is a literal value (non-reactive). Wrapping the literal value with a ref does not restore the reactivity from props, but rather creates a new independent ref.

To maintain the reactivity in the composable, use toRefs or toRef to get the barcodePulse:

const { barcodePulse } = toRefs(props) // ✅
// or
const barcodePulse = toRef(props, 'barcodePulse') // ✅

usePulse(barcodePulse)

demo

  • Related