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

How to conditionally render a component with useDisplay composable (SSR)? #197

Open
igorexa34314 opened this issue Feb 18, 2024 · 36 comments
Assignees
Labels
bug Something isn't working

Comments

@igorexa34314
Copy link

igorexa34314 commented Feb 18, 2024

I'm trying to conditionally render the navigation menu in the 'v-app-bar' based on the viewport size. I am using the mobile property from useDisplay() composable. If it's false, I render the list of links, otherwise the burger icon is rendered. On the local development server everything works fine. But when deploying on netlify, on initial loading, the list of links appears for a moment and then changes to burger button. This behavior is only seen on mobile devices. I have ssrClientHints.viewportSize enabled.

What could this be related to? Maybe I don't quite understand how ClientHints work.

@userquin
Copy link
Owner

userquin commented Feb 18, 2024

A few questions:

  • are you using SSR in local dev environment (SSR should be true)?
  • how do you deploy your app to Netlify (using nuxt build or nuxt generate command)?
  • what are your routeRules or nitro.routesRules/nitro.prerender options?

@igorexa34314
Copy link
Author

  • Yes, im using SSR in in local dev environment (SSR is true by default in nuxt.config.ts)
  • I deploy using nuxt build command
  • I have no routeRules in my nuxt app

@igorexa34314 igorexa34314 changed the title How to conditionally render a component with 'useDisplay' composable (SSR)? How to conditionally render a component with useDisplay composable (SSR)? Feb 18, 2024
@userquin
Copy link
Owner

userquin commented Feb 19, 2024

@igorexa34314 can you provide the Netlify URL and a link to the repo (if public) ?

@igorexa34314
Copy link
Author

1.online-video-cutter.com.mp4

I fixed the code a little bit. Now I found that menu is rendered incorrectly when the viewport width is between my breakpoint and 980px. Although if the width is not in this range, everything works fine.

@userquin This is the website address - https://keksbot.xyz/

@userquin
Copy link
Owner

On my Chrome (Windows) it is working properly even resizing it to 820px (when enabling mobile view a small slide down transition is there: IIRC, on mobile there is a small bug about slide down in SSR, check vuetifyjs/vuetify#15229)

The SSR state seems to be fine:

imagen

HTTP Request Headers:

imagen

@igorexa34314
Copy link
Author

@userquin Could you try opening the site on mobile phone (Android or iOS)?

@userquin
Copy link
Owner

On Chrome (Android) the items shown, I Will check it tmr via usb to check what's happening (can be a problem with css, vuetify or both)

@userquin
Copy link
Owner

@igorexa34314 can you provide the structure you're using? It seems the component to show the items using 1280px but changed to use 820px

If using VToolbar, what's the collapse property you're using?

Maybe it is a problem with mobile-breakpoint prop in the navigation drawer.

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

Try setting :mobile-breakpoint="820": https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VNavigationDrawer/VNavigationDrawer.tsx#L107

EDIT: :mobile-breakpoint="819"

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

The server sending the toolbar with the hamburger, so it seems a problem with the breakpoints, maybe you can change the defaults using display property in vuetify options (update the entries, the code below from https://vuetifyjs.com/en/features/display-and-platform/#options):

display: {
    mobileBreakpoint: 'sm',
    thresholds: {
      xs: 0,
      sm: 340,
      md: 540,
      lg: 800,
      xl: 1280,
    },
  },

imagen

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

@igorexa34314
Copy link
Author

@userquin I add breakpoint from app.config.ts using the 'vuetify:before-create' hook. I checked the breakpoints and everything is correct there.

export default defineNuxtPlugin(nuxtApp => {
  const { mobileBreakpoint } = useAppConfig()
  nuxtApp.hook('vuetify:before-create', ({ vuetifyOptions }) => {
    vuetifyOptions.display = {
      thresholds: {
        ...vuetifyOptions.display?.thresholds,
        lg: mobileBreakpoint
      },
      mobileBreakpoint: 'lg'
    }
  })
})

I also specify mobile breakpoint in useDisplay composable. My navigation bar looks like this:

<template>
  <v-app-bar
    class="app-navbar"
    flat
    color="base"
    :height="isMobile ? navbar.height.mobile : navbar.height.base"
    :elevation="0"
    style="width: 100%; z-index: 1006">
    <div
      class="navbar-container h-100 mx-auto"
      :class="[isMobile ? 'px-4 py-3' : 'pa-5']">
      <v-app-bar-title style="flex: 0 1 auto">
       //...
      </v-app-bar-title>

      <LazyUiBurgerBtn v-if="isMobile" />

      <LazyAppNavMenu v-else />
    </div>
  </v-app-bar>
</template>

<script setup lang="ts">
const { navbar } = useAppConfig().app
const isMobile = useIsMobile()

function useIsMobile = () => {
  const { mobileBreakpoint } = useAppConfig()
  const { mobile } = useVDisplay({ mobileBreakpoint })
  return mobile
}
</script>

I've also tried it without the lazy components as well.

@userquin
Copy link
Owner

do you have a VNavigationDrawer? It seems the problem is in the layout and the nav drawer, I can see the nav drawer styles in server response

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

If I don't use mobile view (size > 1280px) the server sending the page without nav drawer and hamburger, if the size is between 820px and 1280px I see the nav drawer styles (div + navigation-drawer classes) and the hamburger button.

@userquin
Copy link
Owner

if using size < 820px the server sending the nav drawer styles (div + navigation-drawer classes) and the hamburger button.

@userquin
Copy link
Owner

so, it seems a problem with the breakpoints, I don't know why your logic not working, the mobile break point seems to be fine:

imagen

@igorexa34314
Copy link
Author

I render the drawer when isMobile = true. And in mobile version when you click on the burger button, drawer should show up.

<!-- layouts/default.vue -->
<template>
  <v-layout class="app-layout d-flex flex-column">
    <LazyAppDrawer v-if="isMobile" v-model:drawer="drawer" />

    <AppNavbar  @burger-click="drawer = !drawer" />

    <v-main
      class="main pb-8"
      :style="{
        'padding-top': `${isMobile ? navbar.height.mobile : navbar.height.base}px`
      }">
      <Suspense>
        <slot />
      </Suspense>
    </v-main>

    <AppFooter />
  </v-layout>
</template>

<script setup lang="ts">
const { navbar } = useAppConfig().app

const isMobile = useIsMobile()
const drawer = ref(false)

watch(() => !isMobile.value,  () => {
    drawer.value = false
})
</script>
<!-- AppDrawer.vue -->
<template>
  <v-navigation-drawer
    v-model="drawer"
    location="top"
    :mobile-breakpoint="mobileBreakpoint"
    temporary>
    <AppNavMenu class="drawer-menu pt-6" />
  </v-navigation-drawer>
</template>

<script setup lang="ts">
const drawer = defineModel<boolean>('drawer', { default: false })

const { mobileBreakpoint } = useAppConfig()
</script>

@userquin
Copy link
Owner

we need to figure out what's happening with sizes between 820px and 1280px, maybe a bug in vuetify maybe a bug in the breakpoints or maybe both ;)

@userquin
Copy link
Owner

The mobile logic seems to fine: https://github.com/vuetifyjs/vuetify/blob/f8105c2902bc5ca57c92f8f2898c62a6d5fa001e/packages/vuetify/src/composables/display.ts#L169-L207

But, you're modifying only lg and maybe you're breaking the global breakpoints... check the logic in previous link.

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

can you just change mobile-breakpoint in the plugin with the value in the app config?

export default defineNuxtPlugin(nuxtApp => {
  const { mobileBreakpoint } = useAppConfig()
  nuxtApp.hook('vuetify:before-create', ({ vuetifyOptions }) => {
    vuetifyOptions.display = { mobileBreakpoint }
  })
})

@userquin
Copy link
Owner

You can use useNuxtApp().$vuetify.display.mobile.value in the console resizing the window

I'm going to check the logic nav drawer, can you show me the layout.vue?

@userquin
Copy link
Owner

userquin commented Feb 20, 2024

ok, please apply my suggestion in the plugin, you're breaking the breakpoins: https://github.com/vuetifyjs/vuetify/blob/f8105c2902bc5ca57c92f8f2898c62a6d5fa001e/packages/vuetify/src/composables/display.ts#L170-L175

EDIT: remove also the useIsMobile function and use useVDisplay().mobile

@igorexa34314
Copy link
Author

function useIsMobile = () => {
  const { mobile } = useVDisplay()
  return mobile
}

Is it possible to make it like that to not override the default thresholds if there are any?

export default defineNuxtPlugin(nuxtApp => {
  const { mobileBreakpoint } = useAppConfig()
  nuxtApp.hook('vuetify:before-create', ({ vuetifyOptions }) => {
    vuetifyOptions.display ??= {}
    vuetifyOptions.display.mobileBreakpoint = mobileBreakpoint
  })
})

@userquin
Copy link
Owner

you can try both approach, vuetify will merge it, but yeah, that's also fine

@userquin
Copy link
Owner

still there, mobile breakpoint changed but server sending wrong html

@userquin
Copy link
Owner

can you initialize drawer properly in layout.vue?

<!-- layouts/default.vue -->
<template>
...
</template>
<script setup lang="ts">
const { navbar } = useAppConfig().app

const isMobile = useIsMobile()
const drawer = ref(isMobile.value)

watch(() => !isMobile.value,  () => {
    drawer.value = false
})
</script>

@igorexa34314
Copy link
Author

You want it to show up immediately on mobile?

@userquin
Copy link
Owner

upps, I read v-if="drawer"...

@userquin
Copy link
Owner

I'm going to prepare a reproduction with minimal configuration... do you have a discord account?

@igorexa34314
Copy link
Author

If I ask the repo owner to give you access, would it be better for you?

@userquin
Copy link
Owner

sure

@igorexa34314
Copy link
Author

Just don't be alarmed if you see a lot of shitty code ;)

@userquin
Copy link
Owner

do you have discord account?

@igorexa34314
Copy link
Author

Invite sent. My discord nickname is the same as my github username.

@userquin
Copy link
Owner

this one?
imagen

@userquin userquin self-assigned this Feb 20, 2024
@userquin userquin added the bug Something isn't working label Feb 20, 2024
@userquin
Copy link
Owner

userquin commented Feb 20, 2024

SSR Client hints server plugin should be the last one, since we're using order: -25 the vuetify options configured in any app plugin will be ignored, it should have order: 24.

The client plugin should be the first one (the state is there)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants