GithubHelp home page GithubHelp logo

Comments (18)

jamesreggio avatar jamesreggio commented on May 5, 2024 50

There are a couple things happening here, so I'm going to share some background that will hopefully help.

  • persistor.purge() will clear the storage provider (e.g., localStorage), but it doesn't clear the in-memory cache, and it doesn't stop persistence from happening again.
  • persistor.remove() will stop persistence from happening again, but doesn't clear the storage provider or in-memory cache.
  • client.resetStore() will clear the in-memory cache and refetch all queries, but it has no effect on the persistor.

I regret how convoluted the interaction of these concerns is, and it's something we ought to resolve in Apollo Client 3.0. But, until then, here's the order of events I would advise for a logout:

// User clicks 'log out'.
// First: do whatever is necessary in your app to invalidate/clear out the user's session.
// Then do the following:

persistor.pause(); // Pause automatic persistence.
persistor.purge(); // Delete everything in the storage provider.

// If there are views visible that contain data from the logged-out user,
// this will cause them to clear out. It also issues a bunch of network requests
// for data that likely won't be available anymore since the user is logged-out,
// so you may consider skipping this.
client.resetStore();

// Redirect user to login page.
// At this point, the logged out user may close the tab/app.
// If they do, everything should be good: the storage provider will remain cleared,
// and no prior data will be visible upon next use.

// Let's assume the user logs in.
// First: do whatever is necessary to set the user's session.
// Next: you absolutely must reset the store. This will clear the prior user's data from
// memory and will cause all of the open queries to refetch using the new user's session.
client.resetStore();

// Resume cache persistence. The cache storage provider will be empty right now,
// but it will written with the new user's data the next time the trigger fires.
persistor.resume();

Again, I realize how convoluted this is, but login/session management is generally a convoluted thing, because there are hundreds of ways to do it, and it varies quite a bit between native apps vs. single-page apps vs. server-rendered apps.

Perhaps in the future, we could build an Apollo package for managing sessions (and thus Apollo could coordinate all of these actions).

from apollo-cache-persist.

tamlyn avatar tamlyn commented on May 5, 2024 31

Note there is now a client.clearStore() function which does not refetch queries.

from apollo-cache-persist.

davidgoli avatar davidgoli commented on May 5, 2024 5

@jamesreggio this is good info, it would be great to promote your code to the docs and also give and example of usage in a demo app, because this is an extremely common use case

from apollo-cache-persist.

sbrichardson avatar sbrichardson commented on May 5, 2024 4

This code below works, it can be cleaned up, but it double checks a few items to ensure it’s cleared.

The setTimeout ensures an empty persist key gets cleared also, and clears the console from any noise.

SafeStorage is localstorage it just does some extra checks for device etc.

import { safeStorage } from '../data/safeStorage/safeStorage'
import client from '../data/apollo'

const allStorageKeys = storage =>
  storage && typeof storage === 'object' && Object.keys(storage)

const blacklist = [
  'access_token',
  'id_token',
  'nonce',
  'expires_at',
  'email',
  'sub',
  'r_persist',
  'tid',
  'uid'
]

const whitelist = []

const logoutUser = async ({ history, ...props }) => {
  try {

    let b_i = blacklist.length

    while (b_i--) {
      safeStorage.removeItem(blacklist[b_i])
    }

    const remaining = allStorageKeys(safeStorage)

    if (remaining && remaining.length) {
      let r_i = remaining.length
      while (r_i--) {
        if (whitelist.indexOf(remaining[r_i]) === -1) {
          console.warn(
             'logoutUser() - removing non-whitelisted item:',
             remaining[r_i]
           )
          safeStorage.removeItem(remaining[r_i])
        }
      }
    }

    try {
      // clear apollo client cache/store
      if (client && typeof client.resetStore === 'function') {
        client.resetStore()
      }
    } catch (e) {
      console.error('err client', e)
    }

    // clear console in case any app messages
    typeof console.clear === 'function' && console.clear()

    // clear stores again after delay
    setTimeout(() => {
      try {
        let b_i_2 = blacklist.length
        while (b_i_2--) {
          safeStorage.removeItem(blacklist[b_i_2])
        }
        // clear apollo client cache/store
        if (client && typeof client.resetStore === 'function') {
          client.resetStore()
        }
        typeof console.clear === 'function' && console.clear()
      } catch (e) {
        console.error('err client', e)
      }
    }, 2000)
  } catch (e) {
    // if error is caught, try to just clear all localStorage items
    console.error('err 1', e)
    try {
      const k = allStorageKeys(safeStorage)
      if (k && k.length) {
        k.forEach(o => safeStorage.removeItem && safeStorage.removeItem(o))
      }
      if (client && typeof client.resetStore === 'function') {
        client.resetStore()
      }
    } catch (e2) {
      console.error('err 2', e2)
    }
  }
}

export default logoutUser

from apollo-cache-persist.

noicetoit avatar noicetoit commented on May 5, 2024 2

@jamesreggio thank you for the explanation. But what if user wants to switch account and wants to login immediately after log out? Can I purge the local storage and re-creating it with default client state right after user logs out?

from apollo-cache-persist.

sbrichardson avatar sbrichardson commented on May 5, 2024 1

Thanks for those details

from apollo-cache-persist.

jamesreggio avatar jamesreggio commented on May 5, 2024 1

I'm going to close this issue. If anybody needs further clarification, please don't hesitate to ask.

from apollo-cache-persist.

n1ru4l avatar n1ru4l commented on May 5, 2024

Check out this section: https://github.com/apollographql/apollo-cache-persist#advanced-usage

from apollo-cache-persist.

sce9sc avatar sce9sc commented on May 5, 2024

I've tried also deleting the local storage using persistor.purge() but it seems that is is never deleted or it is being repopulated

from apollo-cache-persist.

sce9sc avatar sce9sc commented on May 5, 2024

I've also tried the below steps

  1. persistor.remove();
  2. persistor.purge();

and then
3) persistor.persist()

and the localstorage is populated even though if you query the data is empty

from apollo-cache-persist.

n1ru4l avatar n1ru4l commented on May 5, 2024

@sce9sc Could you please create a reproduction scenario using https://codesandbox.io ?

from apollo-cache-persist.

techyrajeev avatar techyrajeev commented on May 5, 2024

@jamesreggio I am not sure how to access persistor instance from a react component?

from apollo-cache-persist.

n1ru4l avatar n1ru4l commented on May 5, 2024

You can either import it in your file directly or use React.Context to do so:

// cache-persistor.js
import { createContext } from "react";
import { CachePersistor } from "apollo-cache-persist";

const persistor = new CachePersistor({});
const Context = createContext(persistor);

export const CachePersistor = Context.Consumer;

// your-component.js
import React from "react";
import { CachePersistor } from "./cache-persistor";

export function YourComponent() {
  return (
    <CachePersistor>
      {cachePersistor => (
        <button
          onPress={() => {
            // do sth with cachePersistor here
          }}
        >
          Press me
        </button>
      )}
    </CachePersistor>
  );
}

from apollo-cache-persist.

ancyrweb avatar ancyrweb commented on May 5, 2024

@jamesreggio i'm falling into the same case as @noicetoit, any advice on this ? As I see the local state is also purged, and the defaults are not set.

EDIT : actually ended up fixing it like this

 if (this.cachePersistor) {
      this.cachePersistor.pause();
      await this.cachePersistor.purge();
      await this.client.resetStore();
      this.client.cache.writeData({
        data: this.clientStageConfig.defaults
      });
      this.cachePersistor.resume();
    }

from apollo-cache-persist.

tm1000 avatar tm1000 commented on May 5, 2024

A solution without using cachePersistor is client.clearStore() which was briefly mentioned by @tamlyn above.

from apollo-cache-persist.

maltenz avatar maltenz commented on May 5, 2024

a combination of
client.resetStore()
and client.clearStore()
works for me!

from apollo-cache-persist.

johnnyoshika avatar johnnyoshika commented on May 5, 2024

a combination of
client.resetStore()
and client.clearStore()
works for me!

@maltenz I don't think it works as you intended. If you reload the browser, the previous cache will be restore from apollo-cache-persist, as it was never purged from there. You need to clear the memory cache (with client.clearStore()) AND purge the persistence cache with the example provided by @rewieer.

from apollo-cache-persist.

JoaoHamerski avatar JoaoHamerski commented on May 5, 2024

@jamesreggio solution isn't working anymore, at least on vue-apollo, i simply can't reset the cache when the user logout and login. I even let the default code of vue CLI vue add apollo which already have client.resetStore() on logout and login method but nothing happens.

from apollo-cache-persist.

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.