Coder Social home page Coder Social logo

Comments (2)

freddy38510 avatar freddy38510 commented on June 20, 2024

I've played around with this plugin a few days ago.

Instead of using type of window !== 'undefined', you can use !import.meta.env.SSR or process.env.CLIENT. It will be statically replaced by true or false when the app is compiled, allowing tree-shaking of unreachable code.

When a pre-rendered page is fully loaded by the browser, the store is primed with the server-initialized state. But when navigating to subsequent pages (you are in SPA mode now), there is no server-initialized state.

Edit: This part of the comment was irrelevant.

Here's how I managed to take both scenarios into account:
// src/stores/index.js

import { store as createStore } from 'quasar/wrappers';
import { createPinia } from 'pinia';
import { createPersistedState } from 'pinia-plugin-persistedstate';

export default createStore((/* { ssrContext } */) => {
  const pinia = createPinia();

  if (!import.meta.env.SSR) {
    pinia.use(createPersistedState({
      auto: true,
      beforeRestore: ({ store }) => {
        if (store.$state.hasChanged === true) {
          store.$persist();
        }
      },
    }));
  }

  return pinia;
});
// src/stores/example.js

import { defineStore } from 'pinia';

export const useExampleStore = defineStore('example', {
  state: () => ({
    counter: 0,
    data: null,
    hasChanged: false,
  }),
  getters: {
    doubleCount: (state) => state.counter * 2,
  },
  actions: {
    increment() {
      this.counter += 1;
      this.hasChanged = true;
    },
    async fetchData() {
      this.data = await (await fetch('https://someapi.com')).json();
      this.hasChanged = true;
    },
  },
});
// src/components/ExampleComponent.vue

<template>
  <div>
    <div>Direct store</div>
    <!-- Read the state value directly -->
    <div>{{ store.counter }}</div>
    <pre>{{ store.data }}</pre>
    <!-- Use getter directly -->
    <div>{{ store.doubleCount }}</div>


    <!-- Manipulate state directly -->
    <q-btn @click="store.counter--">-</q-btn>
    <!-- Use an action -->
    <q-btn @click="store.increment()">+</q-btn>
  </div>

</template>

<script>
import { useExampleStore } from 'stores/example';
import { onBeforeMount, onServerPrefetch } from 'vue';

export default {
  setup() {
    const store = useExampleStore();

    // this hook is executed at server side only
    onServerPrefetch(async () => {
      await store.fetchData();
    });

    // this hook is executed at client-side only
    onBeforeMount(async () => {
      if (store.hasChanged === false) {
        await store.fetchData();
      }
    });

    return {
      store,
    };
  },
};
</script>

from quasar-app-extension-ssg.

freddy38510 avatar freddy38510 commented on June 20, 2024

The use of ssg/ssr and client-side persistent state leads to two distinct sources of state.

You have one source initialized at build-time, and an other from a storage at client-side.

If these two sources differ, there will be a client-side warning about the hydration mismatch.

You can enable the Quasar manualStoreHydration option, but you'll still have hydration mismatch. This is because the pre-rendered content will have the initial state, which may differ from the persistent state.

There are two ways of solving this problem:

  • The simplest is to use the QNoSsr component.
  • Alternatively, you can try making the pinia persisted state plugin run after hydration is complete.

The disadvantage of these two solutions is that you'll have to manage a kind of loading state, rather than having content that changes abruptly.

For the second solution, I found a not-so-clean way of doing it by using the 'onMounted' hook in the root component "App.vue":

// src/App.vue

<template>
  <router-view />
</template>

<script setup>
import { getActivePinia } from 'pinia';
import { createPersistedState } from 'pinia-plugin-persistedstate';
import { onMounted } from 'vue';

if (process.env.CLIENT) {
  const pinia = getActivePinia();

  pinia?.use((context) => {
    onMounted(() => {
      createPersistedState({
        auto: true,
        beforeRestore: () => {
          console.log('beforeRestore');
        },
        afterRestore: () => {
          console.log('afterRestore');
        },
      })(context);
    });
  });
}
</script>
// src/store/index.js

import { store as createStore } from 'quasar/wrappers';
import { createPinia } from 'pinia';

export default createStore(() => createPinia());

from quasar-app-extension-ssg.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.