Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The value of $mq is not correct on mouted #39

Open
bravelincy opened this issue Jul 22, 2019 · 11 comments
Open

The value of $mq is not correct on mouted #39

bravelincy opened this issue Jul 22, 2019 · 11 comments

Comments

@bravelincy
Copy link

// main.js
Vue.use(VueMq, { 
  breakpoints: {
    xs: 468,
    sm: 768,
    md: 1080,
    lg: Infinity
  }
})

// App.js
{
  mounted () {
    console.log(this.$mq) // sm, but the viewport size was matched `lg`
  }
}
@do-adams
Copy link

I am having this same issue but on a computed property that references $mq. The value comes across as 'sm' despite the browser window being visibly larger than the 'sm' width.

@do-adams
Copy link

do-adams commented Jul 26, 2019

Actually, upon further testing I have determined that the value of $mq for me is correct at mounted() time.

However, peeking into the source code a bit, the vue-mq plugin defaults to breakpoint size sm for all of the Vue lifecycle instance hooks up until mounted(), which causes elements that rely on v-if="$mq === 'sm'" to actually be rendered initially before being removed from the DOM.

In my case, setting the defaultBreakpoint for the plugin to lg fixed the issue.

@supremeo
Copy link

In my case, setting the defaultBreakpoint for the plugin to lg fixed the issue.

That doesn't fix the issue. Resize your browser down and reload the page. You'll see the same issue persist. For the issue to be resolved, defaultBreakpoint would need to be deviceWidth aware and render the appropriate breakpoint at SSR

@flyingL123
Copy link

@do-adams I am having the exact same problem. I am switching layouts depending on the value of $mq:

<template>
    <div class="tw-pt-4">
        <product-body-mobile v-if="$mq == 'sm'"/>
        <product-body-desktop v-else/>
    </div>
</template>

I am finding then when I load the page on a md screen, the mounted hooks are being called for components within the product-body-mobile component. This is really frustrating. Have you tried using the <mq-layout> components instead of v-if to see if that resolves the problem?

@flyingL123
Copy link

That doesn't seem to make a difference based on my testing. I'm pretty confused by this. Isn't this a pretty major issue with the library?

@flyingL123
Copy link

flyingL123 commented Dec 2, 2019

It definitely seems like this shouldn't be necessary, and I'm guessing there are probably a bunch of performance-related reasons not to do this, but in case it helps anyone else, I was able to solve the problem by wrapping everything in a conditional that depends on whether or not the mounted hook has been called:

<template>
    <div class="tw-pt-4">
        <template v-if="didMount">
            <product-body-mobile v-if="$mq == 'sm'"/>
            <product-body-desktop v-else/>
        </template>
    </div>
</template>
data () {
    return {
        didMount: false
    };
},

mounted () {
    this.didMount = true;
}

Again, not thrilled this is necessary, but it seems to work for me and I'm only using this conditional rendering in a few places, so it will have to do for now.

If anyone sees any issues with this, please do let me know.

@Aztriltus
Copy link

Hi @flyingL123, I came to the same conclusion as you did, by using the mounted hook to set the correct layout since $mq defaults to something and changes after it is mounted. So when my web page loads on a tablet+ resolution, it loaded the mobile layout before it changed to the tablet layout after it is mounted, causing the page to look broken at the start.

However, there is still a problem with this 'solution'. When using pre-rendered pages such as the 'nuxt generate' command, the didMount property will stay false as there is no mounted() when generating. Thus, the generated html are all empty since v-if is always false.

I think the best implementation might be a $mq.isLoading feature to check if the mq has fully loaded, before setting the $mq property. I have tried other ways but nuxt doesn't seem to allow me to set a new mode i.e. nuxt generate -- --mode generate. I thought I could do didMount: process.env.NODE_ENV === 'generate' but it still doesn't work. Man... I'm out of ideas here.

@DennisMaass
Copy link

DennisMaass commented Dec 12, 2019

I fixed it for clientside rendering with

Vue.use(VueMq, { 
  breakpoints: {
    xs: 468,
    sm: 768,
    md: 1080,
    lg: Infinity
  },
  defaultBreakpoint: ""
})

So the initial value is not "sm" and in principle it does the same as

mounted () {
    this.didMount = true;
}

@flyingL123
Copy link

flyingL123 commented Dec 13, 2019

Hi @DennisMaass this actually didn't work for me. It solved one problem but then created the same problem in reverse. With your method, when I load the page on a desktop screen, the mobile mounted hooks are correctly not called. However, now when I load the page on a mobile screen, the desktop hooks get called. So it's the same problem as before, but in reverse.

Are you seeing that same behavior?

@Aztriltus
Copy link

Aztriltus commented Dec 14, 2019 via email

@Aztriltus
Copy link

Aztriltus commented Dec 14, 2019

So I've been thinking about this issue for sometime now.

My problem was when I use my 'mobile' breakpoint as defaultBreakpoint, loading my webpage in 'tablet' or 'desktop' breakpoints would appear broken before $mq is correctly set to 'tablet' or 'desktop'. So it'd flash the 'mobile' layout for about 1-2s before my layout changes to the correct 'tablet or 'desktop' layouts.

My solution to this problem was using v-show on the root-most element that is NOT <template>

<div id="app" v-show="isLoaded">
  <template v-if="$mq === 'mobile'> ... </template>
  <template v-else> ... </template>
</div>
data() {
  return {
    isLoaded: false
  }
},
mounted() {
  this.isLoaded = true
}

When using 'nuxt generate', the mounted hook will not be called, thus isLoaded will always be false. Since I used v-show instead of v-if, the entire app will simply be hidden and still be available in the DOM, allowing my meta-tags to work. Previously, I tried v-if="isLoaded" and my webpages would come up empty.

I hope this would help those who statically generate their apps while using breakpoints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants