skip to Main Content

I am developing a nuxt app which needs to render different components based on my window width. And also will send a request to create a session, in which one of the header parameter is device width. Here is my approach to do that:

Code in my store:

//index.js
export const state = () => ({
  device_width: null,
  session_data : {},
 
})

export const mutations = {
  set_device_width(state, payload) {
    return state.device_width = payload;
  },
  set_session_data(state, payload){
     return state.session_data = payload
  }
}
export const actions = {

  //server init action to initialize the app with some necessary data
  async nuxtServerInit({ commit }) {

    
    if (process.browser) {
      commit('set_device_width', window.innerWidth);
    }
      var device_type = "";
      if (this.state.device_width < 768) {
        device_type = "mobile";
      } else if (this.state.device_width > 768) {
        device_type = "desktop";
      }
      var sessionData= await axios(...//api request with 'device_type' in header//....)
      commit('set_session_data', sessionData)

}

then in my templates I am using computed method to get the value.

computed:{
  isMobile(){
    return this.$store.state.device_width<768
  }
}

Now when I am keeping the screen size under 768, it works just fine. But in the case of desktop mode, full screen, it is always starting as isMobile==true for a few sec. Then isMobile is becoming false and automatically the desktop component is getting loaded. But for that few second I can see the mobile UI, and mainly my session data is always getting created with "device_type: mobile". Also as the page is initially starting with mobile UI, the SEO elements of my desktop UI is not working. How can I solve this? I just need to determine the screen size and store it before the initialization of the app. I thought serverInit action was the way to do that.

2

Answers


  1. you cannot get any device info on serverside, nuxtServerInit executes at serverside and it has no clue about the user device, therefore you cannot use window object in it.

    alternative would be getting the device’s width in a mounted or created cycle of your layouts and committing it to the store, but these will happen after initializing your app.

    Login or Signup to reply.
  2. As tony said, it should be more of a CSS solution for the biggest part.

    If you still want to have the device somewhere, you can use fevid solution, here is some code to make it more visual.

    /layouts/LayoutDefault.vue

    <script>
    import { throttle } from 'lodash-es'
    
    const watchResize = throttle(function () {
      console.log('resized properly')
      // here you should mutate your `device_type` via a Vuex mutation/action
      // and make your axios call by preferably fetching either a const/let variable
      // or a global vuex state
    }, 1000)
    
    export default {
      mounted() {
        window.addEventListener('resize', watchResize)
      },
    }
    </script>
    

    I do recommend using throttle, install it with yarn add -D lodash-es because watching for a resize is a heavy watcher and it may trigger many times, hence make your UI sluggish.


    PS: do not use this in a middleware, otherwise the eventListener will be plugged on each route navigation.
    If you are using several layouts, it would be a good idea to unmount the watcher in a beforeDestroy() hook.

    If you want to have more details on Nuxt’s lifecycle, you can check this page: https://nuxtjs.org/docs/2.x/concepts/nuxt-lifecycle/#server
    Here, you can see that nuxtServerInit is indeed only server side hence the name.


    EDIT: this module looks nice for your use-case: https://github.com/nuxt-community/device-module

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search