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

Reactivity removed on refresh #34

Closed
fdabek1 opened this issue Feb 22, 2018 · 9 comments
Closed

Reactivity removed on refresh #34

fdabek1 opened this issue Feb 22, 2018 · 9 comments

Comments

@fdabek1
Copy link

fdabek1 commented Feb 22, 2018

I am having trouble with my store elements not continuing to be reactive after refreshing the page. My state to start is empty such that:

const state = {
  items: [],
};

I then am using axios to get information from an API and then pushing objects into this array. Below is my mutation:

loadData(state, response) {
    response.items.forEach(function(item) {
      state.items.push(item);
    });
    // Vue.set(state, 'items', response.items);
  },

When I inspect this property in the console, I can see that the reactive getters and setters are added onto these objects within the array. However, when I refresh the page and inspect these objects, the array is reactive but the actual objects are not.

How can I fix this without having to manually go through and fix this on every single module? (I tried to do a global Vue.set() on the state, but that didn't fix it either.)

@fdabek1
Copy link
Author

fdabek1 commented Feb 22, 2018

For anybody that is struggling with this same issue, I just implemented a quick recursive function that solves this solution for now. This is basically a hack so I am hoping that there is a better way to overcome this.

function makeReactive(state) {
  if (typeof state !== 'object') return;

  Object.keys(state).forEach(function (key) {
    if (state[key] !== null && state[key] !== undefined) {
      Vue.set(state, key, state[key]);
      makeReactive(state[key]);
    }
  });
}

export const actions = {
  initial({rootState}) {
    makeReactive(rootState);
  },
};

Just call the action as the first thing on the load of the page.

@championswimmer
Copy link
Owner

Try using with the strict mode mutation (as mentioned on the README)

@fdabek1
Copy link
Author

fdabek1 commented Feb 23, 2018

@championswimmer But the documentation says not to use strict mode in production. So what would be the solution for getting it to work in production?

@j-maas
Copy link

j-maas commented Feb 23, 2018

I think we have the same problem. I have tried playing around with it for the last half hour but I just cannot figure out what causes it to happen.

Reproduction

The code I've used to test this is published as a reproduction repo.

  • Launch the page with yarn serve.
  • Hit the button to add some items that are not from the default state.
  • Reload the page. (May or may not make the newly added items disappear.)
  • Play around with the delay values.

Remarks

Notice that the items from the default state always appear, but the ones only stored in the local storage go sometimes missing.

As I've indicated in the code, the only thing that was always true was that it would not display the state when the state was restored after Vue had loaded.
But even if the state was loaded earlier than Vue, with very low delay values, the items would still sometimes disappear.

I also noticed that time travel using the devtools is broken for me on this repo, which is not the case for my production code. In the production code, I can fix the state by commiting the RESTORE_MUTATION or traveling back to the base state and re-applying the RESTORE_MUTATION. With the reproduction repo, this somehow is broken. Even adding new items using the button does not fix this.
This supports @fdabek1's statement that the reactivity breaks.

My hunch is that some work is still being done in constructing the store when Vue is initialized. Waiting long enough for all the work in the store to be done fixes the issue.

@championswimmer
Copy link
Owner

@fdabek1

Do not use strict mode in production, just use the mutation.

Basically -

  1. Use vuex-persist as if strict mode is on
  2. But do not actually turn on strict mode.

Hope you get it ?

@philwolstenholme
Copy link

@championswimmer I am seeing this behaviour even with the strict mode mutation in use.

It looks like @y0hy0h 's example repo uses the strict mode mutation too: https://github.com/Y0hy0h/vuex-persist-premature-load/blob/master/src/main.js

@NicoAssinkSqills
Copy link
Contributor

NicoAssinkSqills commented Mar 21, 2018

I think I see what the bug is, but I'm not yet sure about the best solution, so maybe we can discuss this.
In the mutation, $set is called with two instead of three arguments. I think the mutation of the state is not caused by the $set call, but by the (lodash) merge function, which mutates its first argument.
If this line:
(this as any)._vm.$set(state, merge(state, savedState))
is replaced by:
merge(state, savedState)
The behaviour stays exactly the same.

The first step to the solution may be to add a first argument to merge: merge({}, state, savedState), so that a new object is created, and the state is not (yet) mutated.
I am not sure about how to $set the complete state. Maybe this is not even possible, and the root properties must be iterated and $set one by one?

@raphaelarias
Copy link

We just installed the latest version, and we still have this bug. Is there anything else we should do to fix it?

@izziaraffaele
Copy link

I had the same issue but I wasn't able to find a working solution so I decided to switch to Vuex-persistedstate which does not have this issue and provides almost the same functionalities as this package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants