I’ll preface this question by saying I’m very new to the composition API so I’m still trying to figure out the best practices. I’m writing a useResizeObserver
composable function using Vue’s composition API in order to track dimension changes on a target element. Because I have to wait for the element to be mounted, I can’t call my composable from top-level in the setup()
method on my component as most examples show, but have to call it from onMounted()
instead, where I have access to my element’s ref
.
onMounted(async () => { elementDimensions.value = useResizeObserver(modalContent.value); }
This forced me to have another ref
that I named elementDimensions
actually declared at the top level of the setup()
function, which I initialise to null
.
setup(props) { const elementDimensions = ref(null); const modalContent = ref(null); ... }
Here is the useResizeObserver
function itself:
export default function useResizeObserver(element) { const elementHeight = ref(0); const elementWidth = ref(0); const resizeObserver = new ResizeObserver(entries => { elementHeight.value = entries[0].contentRect.height; elementWidth.value = entries[0].contentRect.width; }); if (element) { resizeObserver.observe(element); } onUnmounted(() => { resizeObserver.disconnect(); }); return { elementHeight, elementWidth }; }
This actually works well to give me what I want but I’m wondering if there’s a better way to achieve this. The way things are implemented right now, I end up with “nested” refs, since I end up wrapping elementHeight
and elementWidth
(which are already refs) into another ref inside the component (elementDimensions
). Is there a better recommended way of doing this when you need to pass an element to a composable from onMounted()
?
Advertisement
Answer
Composition functions are supposed to be used directly in setup
, any other uses depend on the implementation and need to be verified.
Refs are basically objects that allow to pass a value by reference rather than by value. One of their uses is to pass a ref early and access when a value is up-to-date.
It should be:
setup(props) { const modalContent = ref(null); const elementDimensions = useResizeObserver(modalContent); ... }
and
export default function useResizeObserver(element) { const elementHeight = ref(0); const elementWidth = ref(0); let resizeObserver; onMounted(() => { if (element.value) { resizeObserver = new ResizeObserver(...); resizeObserver.observe(element.value); } } onUnmounted(() => { if (resizeObserver) resizeObserver.disconnect(); }); return { elementHeight, elementWidth }; }