vuexorm in ssr hydration issue



  • Data isn’t hydrating properly when I use:

    items:

    <template>
      <q-page padding class="flex">
        <div class="q-pa-md">
          <div class="q-col-gutter-md row items-start">
            <q-card flat class="col-12">
              <h3 class="text-primary">Shop</h3>
              <h2 class="text-primary">BE FASHION</h2>
            </q-card>
    
            <ItemContent v-for="item in items" :key="item.id" :item="item" />
          </div>
        </div>
      </q-page>
    </template>
    
    <script type="text/javascript">
    import Item from "../store/models/Item";
    export default {
      name: "Shop",
      components: {
        ItemContent: () => import("components/ItemConent")
      },
      computed: {
        items: () => Item.all()
      },
     preFetch() {
        return Item.$fetch().then(response => {
          console.log("success", response);
        });
      }
    };
    </script>
    

    component - itemcontent:

    <template>
      <q-page class="flex flex-center">
        <q-card flat class="main-card flex">
          <q-card-section>
            <router-link :to="{ name: ROUTE_NAME_ITEM, params: { id: item.id } }">
              <q-card
                dark
                shadow-transition
                bordered
                class="bg-secondary hover-shadow my-card"
              >
                <q-card-section>
                  <q-img
                    :src="item.image"
                    class="item-image"
                    style="width: 250px; height: 280px;"
                    alt="11XI products"
                  />
                  <div class="text-h6">{{ item.title }}</div>
                  <div class="text-subtitle2">By: {{ item.designer }}</div>
                </q-card-section>
    
                <q-separator dark inset />
    
                <q-card-section>
                  {{ item.price }}
                </q-card-section>
              </q-card>
            </router-link>
          </q-card-section>
        </q-card>
      </q-page>
    </template>
    <script>
    import { ROUTE_NAME_ITEM } from "../constants";
    export default {
      name: "ItemContent",
      props: {
        item: {
          type: Object,
          required: true
        }
      },
      data: () => ({
        hovered: false,
        ROUTE_NAME_ITEM
      })
    };
    </script>
    

    vuexorm index.js:

    import Vue from "vue";
    import Vuex from "vuex";
    import VuexORM from "@vuex-orm/core";
    import Item from "../store/models/Item";
    import VuexORMAxios from "@vuex-orm/plugin-axios";
    import http from "../store/http";
    import createPersistedState from "vuex-persistedstate";
    import User from "../store/models/User";
    
    Vue.use(Vuex);
    
    const database = new VuexORM.Database();
    database.register(Item, item);
    database.register(User);
    
    VuexORM.use(VuexORMAxios, {
      database,
      http
    });
    
    const VuexORMPlugin = VuexORM.install(database);
    
    export default function({ ssrContext }) {
      const plugins = [];
      plugins.push(VuexORMPlugin);
    
      if (!ssrContext) {
        plugins.push(
          createPersistedState({
            filter: ({ payload }) => (payload ? payload.entity !== "users" : true)
          })
        );
      }
    
      const Store = new Vuex.Store({
        modules: {
    
        },
    
        plugins,
    
        // enable strict mode (adds overhead!)
        // for dev mode only
        strict: process.env.DEV
      });
    
      return Store;
    }
    

    item model:

    import { Model } from "@vuex-orm/core";
    
    export default class Item extends Model {
      static get entity() {
        return "api/items";
      }
    
      static fields() {
        return {
          id: this.string(""),
          title: this.string(""),
          summary: this.string(""),
          status: this.string(""),
          designer: this.string(""),
          description: this.string(""),
          image: this.string(""),
          price: this.number(0),
          cart: this.number(0)
        };
      }
    
      static methodConf = {
        methods: {
          $update: {
            http: {
              method: "patch"
            }
          }
        }
      };
    }
    

    It doesn’t load anything on the page and or it doesn’t throw any errors either. There’s no errors and or give a response in console. The only thing that happens is when I load the page for the first time it shows half the page moved to the left and or loads slow.



  • @bellagrunt said in vuexorm in ssr hydration issue:

    computed: {
    items: () => Item.all()
    },

    Interesting. I don’t know how SSR mode works in the context of vueorm. BTW this fragment is one of the first I would check - I would put some console.log or debugger in this:

      computed: {
        items: () => Item.all()
      },
    

    something like this:

      computed: {
        items () {
            let ret = Item.all()
            // debugger OR console.log(ret)
            return ret
        }
      },
    


  • Screenshot 2019-09-19 at 09.04.16.png

    Thanks for getting back to me. Same thing happened with console.log.



  • The interesting part is that when I don’t try to use preFetch and load the data on the page with the hydration error —

      created() {
        Item.$fetch()
          .then(response => {
            console.log("success", response);
          })
          .catch(response => {
            console.log("error", response.status, response.errors);
            this.errors = response.errors;
          });
      }
    

    In terminal it gets a “undefined” but when I do something like:

      preFetch() {
        return Item.$fetch().then(response => {
          console.log("success", response);
        });
      },
    

    It doesn’t load anything on the page but I don’t get any errors or undefined



  • @bellagrunt Hmm, I didn’t work with SSR, so can’t say about prefetch. Anyhow, from Vue’s pov, if you’re using “created()” then imho it’s quite early in component lifecycle:

    https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

    In typical situation, I would use a “mounted()”.

    Does your solution works without SSR in “normal” SPA mode?



  • yea, it works fine without ssr (spa) but i need ssr for this project tried mounted before and still gave me the hydration error. i asked the vuexorm team as well. came up with:

      preFetch() {
        return this.$axios
          .get("http://localhost:8000/api/items")
          .then(response => {
            Item.insert({ data: response.data });
            console.log("success", response);
          })
          .catch(response => {
            console.log(response.error);
            this.error = response.error;
          });
      }
    

    Data would show maybe 30% of the time with no undefined. Not sure if I mentioned but I’m using the vuexorm-axios plugin. I was thinking of calling in axios separately from vuexorm and not use the axios plugin.



  • I think I got it to work, actually. But I was wondering, how do you validate if preFetched worked? I set up the same exact project in vuex and modified my vuexorm project. got the same results of the website rendering to the left when loading the first time.



  • The only slight difference is that it on terminal i dont get an “undefined” anymore and it loads a little quicker.


Log in to reply