0

I have a component that needs to calculate some values using the DOM, and so I have the onMounted() lifecycle hook. In onMounted() I calculate some values (technically, they're computed properties) dependent on DOM elements.

I then use the values found in another computed property, leftOffset. I need to use leftOffset in template (it changes some CSS, not really relevant).

Below is my setup():

setup() {
    let showContent = ref(false);
    
    let windowWidth = ref(null);
    let contentHider = ref(null);

    let contentHiderXPos ;
    let contentHiderWidth ;
    let leftWidth;

    onMounted(() => {
        // The DOM element will be assigned to the ref after initial render
        windowWidth = ref(window.innerWidth);

        contentHiderXPos = computed(() => contentHider.value.getBoundingClientRect().left);
        contentHiderWidth = computed(() => contentHider.value.getBoundingClientRect().width);
        leftWidth = computed(() => contentHiderXPos.value + contentHiderWidth.value);
    });

    let leftOffset = computed(() => {
        return -(windowWidth.value - leftWidth.value)
    });

    return {
        contentHider,
        leftOffset,
    }

contentHider references a the DOM element of one of the divs defined in template.

My problem that leftOffest.value is undefined, because it tries to access windowWidth.value and leftWidth.value, which are also undefined. I've also tried putting leftOffset inside onMounted(), but then I can't access it from template (it's undefined).

How can I re-structure my code so that leftOffset can both be accessed from template and can also access the values found in onMounted()?

I've searched online, but couldn't find anything specific to the composition API.

1 Answer 1

1

Your usage of the ref is wrong. Follow the comments in the below snippet.

Also this is assuming that you do not want the window.innerwidth to be reactive.

// dont create another ref => you are trying to assign a new object here, thus breaking the reactivity
// windowWidth = ref(window.innerWidth);
// do this instead
windowWidth.value = window.innerWidth

If you want the innerWidth to be reactive, you have to use the native event listener like this;

const windowWidth = ref(window.innerWidth)
onMounted(() => {
    window.addEventListener('resize', () => {windowWidth.value = window.innerWidth} )
})
onUnmounted(() => {
    window.removeEventListener('resize', () => {windowWidth.value = window.innerWidth})
}) 
Sign up to request clarification or add additional context in comments.

6 Comments

If I made windowWidth a computed property, would I still need to add event listeners to the window to make innerWidth reactive?
Yes, window properties are not reactive in Vue
what's the point of removing the event listener?
Because if the component is remounted then another event listener will be registered and both listeners will get executed. It’s not efficient and could be error prone too.
That’s ok. You need to tell which function to remove from the registered event listeners.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.