Issue with reactivity in Vue with Pinia and router caching pages

It can be the dumbest question, but I think not.

Lets imagine you have an app that has a login, donwloads some data and then you can log out.
Lets imagine you have 2 pages. So you step on all of them and you get both pages loaded in the dom, one of them with ion-page-hidden. There you have a variable acessing some data that you know does exists because you did a login. The thing is that, when you are in the second page, you wipe some information, let’s say you do a logout. Then, as in the dom the first page is still loaded, and I assume reactivity is still “running”, there is an error on the first page because data can not be accessed.
That’s not how it is supposed to work in a regular webapp, because the complaining dom is not loaded and you don’t even want it to be.

I’ve read why is it done, but the question is how am I supposed to avoid this issue.
A v-if in the complaining page does not seem to do the job, either.

How to reproduce:
git clone [text](https://github.com/Pijuli/ionic-vue-pinia-fail)
npm ci
npm run serve

go to localhost:8080
Open navigator console
Navigate to the other page with the button
Wipe the data

What to expect:
See console complains

Again, this might be dumb, but I’m not seeing how to proceed with it.
Thank you <3

I’m having major issues with this… like blocking issues T_T

this is not an issue of caching pages, it is about checking for errors appropriately. you are not checking for errors in the state manager. Your getter is always assuming there are objects in the array, making the change below should resolve your issue.

  getters: {
    getFirstComplexArrHey: (state): any => {
      if (state.complexArr?.length) {
        return state.complexArr[0].deeper.hey
      } else {
        return null;
      }
    }
  },

Hey Aaron, thanks for the reply.

This does not fix the fact that the template (Actually a view that is hidden by the router but IN the DOM) is trying to access an object that has been wiped out. And, therefore, the error is still present. Which makes me need to add a v-if in the ion-page with, as many checks, as accesses to variables the template has.
And also the fact that if I’m returning any and accessing even a deeper property it won’t let me because of the type check.
And this is because of the router. In a normal vue web/app you don’t need to protect those accesses because the DOM is clean and you will only paint a thing when you know it’s there.

So, as for now, the only fix that I have found is to protect the ion-page with a v-if of the data I want to access and remove it from the DOM, and that is not the idea of the router keeping the html in the DOM.

I tried to explain myself as good as I know, but I can extend the code if I wasn’t clear enough!

Thank you again!

As someone that has been writing apps using ionic for quite a awhile, I think you are overthinking this issue.

I very rarely worry about this issue when building apps for paying clients and performance has not been an issue. In the end, the page renders are fast and errors only occur if you are not properly handling error conditions.

Build your app and deal with the errors appropriately and you will be fine.

As someone that has been writing web and webapps using Vue2 for 5 years, yeah, I found this behaviour quite annoying. But I’ll deal with it. Thanks for the encouragement :ok_hand:

Just to give my two cents. I am using Vue and Vuex with TypeScript (wish I was using Pinia :slight_smile:).

How I handle this is that my store is initialized with a default state (empty objects). So upon logout, I clear the store by re-initializing it to the default state (by calling resetStore).

Example

// state.ts
export const state: State = getEmptyState()

export function getEmptyState(): State {
    return {
        communities: new CommunityCollection(),
        communityMembers: new Array<CommunityMemberModel>(),
    }
}

// store/index.ts
export function resetStore(passedState?: State): void {
    store.replaceState(passedState ?? getEmptyState())
}

// community-collection.ts
export class CommunityCollection {
    items = items = new Array<CommunityModel>()
    last_updated = DateTimeHelper.minDate()
}

// community-member-model.ts
export class CommunityMemberModel {
    community_id = 0
    user_id = 0
    name = ''
    is_approved = false
    is_admin = false
    is_self = false
    last_updated = DateTimeHelper.minDate()
}

Within my components, I mostly use computed properties to get data from my store. I typically handle undefined values by initializing an empty object. This way the template never has to worry about undefined or null values. Of course, this should never happen as upon login or another event, the data should be re-loaded into the store.

Example

// CommunityView.vue
computed: {
    community(): CommunityModel {
        return state.communities.items.find(c => c.id === this.communityId) ?? new CommunityModel()
    },
},
2 Likes

That makes sense. I think I’ll be trying the same approach. That way, the object will be empty but at least the template will have an object. Thank you for the tip!
Cheers!

1 Like