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

Store state losing reactivity when used with router Vue 2 #370

Closed
dyamon-cz opened this issue Feb 25, 2021 · 8 comments
Closed

Store state losing reactivity when used with router Vue 2 #370

dyamon-cz opened this issue Feb 25, 2021 · 8 comments
Labels
bug Something isn't working v1 issues related to v1 for Vue 2

Comments

@dyamon-cz
Copy link

Reproduction

Hello, first of all I would like to say that I love pinia and this direction and I'm actually trying to use it in production with Vue2 and composition-api library.

I have an issue which I would like to help with. Issue can be easily reproduced with new vue-cli project, router with history mode, Typescript and Babel without class components.

Screenshot 2021-02-25 at 3 40 45 PM

Install composition-api and pinia for Vue2 and register composition-api in main.ts by Vue.use().

Next just need two component, store from documentation here on github and router.

stores/test-store.ts

import { createStore } from "pinia"; // btw can't find defineComponent method

export const useMainStore = createStore({
  // name of the store
  // it is used in devtools and allows restoring state
  id: "main",
  // a function that returns a fresh state
  state: () => ({
    counter: 0,
    name: "Eduardo",
  }),
  // optional getters
  getters: {
    doubleCount() {
      return this.counter * 2;
    },
    doubleCountPlusOne() {
      return this.doubleCount * 2;
    },
  },
  // optional actions
  actions: {
    reset() {
      // `this` is the store instance
      this.counter = 0;
    },
  },
});

views/MainComponent.vue

<template>
  <div>
    <h1>{{ main.counter }}</h1>
    <router-link to="/second" tag="button">go</router-link>
    <button @click="main.counter++">click</button>
  </div>
</template>

<script>
import { useMainStore } from "@/stores/test-store";
import { computed, defineComponent } from "@vue/composition-api";

export default defineComponent({
  setup() {
    const main = useMainStore();
    console.log(main.counter);
    main.counter = main.counter + 1;
    console.log("count");
    console.log(main.counter);

    return {
      // gives access to the whole store
      main,
      // gives access only to specific state
      state: computed(() => main.counter),
      // gives access to specific getter; like `computed` properties
      doubleCount: computed(() => main.doubleCount),
    };
  },
});
</script>

views/SecondComponent.vue

<template>
  <div>
    <h1>Test</h1>
  </div>
</template>

<script>
import { computed, defineComponent } from "@vue/composition-api";

export default defineComponent({
  setup() {
    return {};
  },
});
</script>

router/index.ts

import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import MainComponent from "../views/MainComponent.vue";
import SecondComponent from "../views/SecondComponent.vue";

Vue.use(VueRouter);

const routes: Array<RouteConfig> = [
  {
    path: "/",
    name: "Main",
    component: MainComponent,
  },
  {
    path: "/second",
    name: "Second",
    component: SecondComponent,
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

export default router;

After setting up the app there are to buttons, go to next route button and click button, there is also logic in MainComponent.vue setup() function to increment counter every time and to console.log() to make sure setup function is being called.

When you serve the app everything works fine, counter gets automatically incremented to 1 and when you click on button it keeps incrementing. However when you get to the second route using go button and back using history back button, setup function is triggered but counter is not incremented and click button also not incrementing anymore. Event of the click button is being fired just reactivity of store state seems broken. (even if you not use browser back history btn but setup router-link in the next component and redirect back it's gonna be the same).

Any ideas what could be the issue and potential workaround?

Thank you very much for help!

Screen.Recording.2021-02-25.at.4.13.52.PM.mov
@dyamon-cz
Copy link
Author

Just found the workaround, basically $state has correct reactivity, however documentation here suggests that to expose the entire state we can just pass the store into the template. main.$state holds correct reactive references, seems like store object does not.

@posva
Copy link
Member

posva commented Feb 25, 2021

Hi, I'm glad you like it! I will need a boiled down repro with no ts, Babel, lint, tests, etc (because they have no influence) that I can run

@posva posva added the need repro This issue couldn't be reproduced label Feb 25, 2021
@dyamon-cz
Copy link
Author

Alright, I have created a repo with Vue app only with router, no typescript, babel etc.

you can just

git clone https://github.com/dyamon-cz/pinia-bug-store-state.git
cd pinia-bug-store-state
npm install
npm run serve

Step 1: clicking the "click" button
Step 2: click "go" button
Step 3: go back in browser history
Step 4: click the "click" button (no longer works)

@dyamon-cz
Copy link
Author

Oh and one more think just notice that npm install pinia does not have latest function

import { defineStore } from 'pinia' // this does not exists

Instead old function must be still used

import { createStore } from "pinia";

@posva
Copy link
Member

posva commented Feb 27, 2021

This is indirectly the same as #255 for v2 and will require a similar fix that will lead to the v1 of Pinia. It is planned 🙂 . That will also include the (already implemented) changes to defineStore() and public properties (they all start with $ now to avoid collisions) #253

@dyamon-cz
Copy link
Author

thank you! I will check those issues out

This is indirectly the same as #255 for v2 and will require a similar fix that will lead to the v1 of Pinia. It is planned 🙂 . That will also include the (already implemented) changes to defineStore() and public properties (they all start with $ now to avoid collisions) #253

@dyamon-cz
Copy link
Author

I checked those issues and vuejs/rfcs#212. Does it mean that component is disposing state on the store root only? When I try to wrap root state of the store in another object everything works as expected and reactivity won't get broken.

  state: () => ({
    innerState: { // solves the issue
      counter: 0,
      name: "Eduardo",
    },
  }),

@posva posva added bug Something isn't working v1 issues related to v1 for Vue 2 and removed need repro This issue couldn't be reproduced labels Mar 1, 2021
posva added a commit that referenced this issue Mar 3, 2021
Fix #370

BREAKING_CHANGE: It's now necessary to create a pinia instance and
install it:
  ```js
  import { createPinia } from 'pinia'

  const pinia = createPinia()
  Vue.use(pinia)
  ```
  The `pinia` instance can be passed to `useStore(pinia)` when called
  outside of a `setup()` function. Check the SSR section of the docs for
  more details.

BREAKING_CHANGE: `setActiveReq()` and `getActiveReq()` have been
replaced with `setActivePinia()` and `getActivePinia()` respectively.
`setActivePinia()` can only be passed a `pinia` instance created with
`createPinia()`.

BREAKING_CHANGE: Since req as a parameter was replacetd with `pinia`,
`getRootState` is no longer necessary. Replace it with
`pinia.state.value` to **read and write** the root state`.

BREAKING_CHANGE: `PiniaSsr` is no longer necessary and has been removed.
posva added a commit that referenced this issue Mar 3, 2021
Fix #370

BREAKING_CHANGE: It's now necessary to create a pinia instance and
install it:
  ```js
  import { createPinia, PiniaPlugin } from 'pinia'

  const pinia = createPinia()
  Vue.use(PiniaPlugin)

  new Vue({
    el: '#app',
    pinia,
    // ...
  })
  ```
  The `pinia` instance can be passed to `useStore(pinia)` when called
  outside of a `setup()` function. Check the SSR section of the docs for
  more details.

BREAKING_CHANGE: `setActiveReq()` and `getActiveReq()` have been
replaced with `setActivePinia()` and `getActivePinia()` respectively.
`setActivePinia()` can only be passed a `pinia` instance created with
`createPinia()`.

BREAKING_CHANGE: Since req as a parameter was replacetd with `pinia`,
`getRootState` is no longer necessary. Replace it with
`pinia.state.value` to **read and write** the root state`.

BREAKING_CHANGE: `PiniaSsr` is no longer necessary and has been removed.
posva added a commit that referenced this issue Mar 4, 2021
Fix #370

BREAKING_CHANGE: It's now necessary to create a pinia instance and
install it:
  ```js
  import { createPinia, PiniaPlugin } from 'pinia'

  const pinia = createPinia()
  Vue.use(PiniaPlugin)

  new Vue({
    el: '#app',
    pinia,
    // ...
  })
  ```
  The `pinia` instance can be passed to `useStore(pinia)` when called
  outside of a `setup()` function. Check the SSR section of the docs for
  more details.

BREAKING_CHANGE: `setActiveReq()` and `getActiveReq()` have been
replaced with `setActivePinia()` and `getActivePinia()` respectively.
`setActivePinia()` can only be passed a `pinia` instance created with
`createPinia()`.

BREAKING_CHANGE: Since req as a parameter was replacetd with `pinia`,
`getRootState` is no longer necessary. Replace it with
`pinia.state.value` to **read and write** the root state`.

BREAKING_CHANGE: `PiniaSsr` is no longer necessary and has been removed.
@posva
Copy link
Member

posva commented Mar 4, 2021

Fixed in #379

@posva posva closed this as completed Mar 4, 2021
posva added a commit that referenced this issue Mar 8, 2021
Fix #370

BREAKING CHANGE: It's now necessary to create a pinia instance and
install it:
  ```js
  import { createPinia, PiniaPlugin } from 'pinia'

  const pinia = createPinia()
  Vue.use(PiniaPlugin)

  new Vue({
    el: '#app',
    pinia,
    // ...
  })
  ```
  The `pinia` instance can be passed to `useStore(pinia)` when called
  outside of a `setup()` function. Check the SSR section of the docs for
  more details.

BREAKING CHANGE: `setActiveReq()` and `getActiveReq()` have been
replaced with `setActivePinia()` and `getActivePinia()` respectively.
`setActivePinia()` can only be passed a `pinia` instance created with
`createPinia()`.

BREAKING CHANGE: Since req as a parameter was replacetd with `pinia`,
`getRootState` is no longer necessary. Replace it with
`pinia.state.value` to **read and write** the root state`.

BREAKING CHANGE: `PiniaSsr` is no longer necessary and has been removed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working v1 issues related to v1 for Vue 2
Projects
None yet
Development

No branches or pull requests

2 participants