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)