apollographql / apollo-link-state

✨ Manage your application's state with Apollo!
MIT License
1.4k stars 100 forks source link

Can't restore state from SSR _and_ use `defaults` #253

Open leebenson opened 6 years ago

leebenson commented 6 years ago

Specifying defaults in a call to withClientState() always overwrites the local cache, even if cache.restore(window.__APOLLO_STATE__) is passed as the cache property.

My assumption would be that restoring a cached state would take precedence over defaults, and only an explicit call to client.resetStore() would reset to defaults.

Currently, I am working around it as follows:

export default function createState(cache: InMemoryCache): ApolloLink {

  const opt: ClientStateConfig = {
    cache: SERVER ? cache : cache.restore((window as any).__APOLLO_STATE__), // <-- restore on the client
    resolvers: {
      Mutation: {
        // sample mutation to toggle the `active` state
        toggleActive(_root: any) {
          const data = cache.readQuery<IState>({ query: getStateQuery });
          data.active = !data.active;

          cache.writeData({ data });

          return data;
        },
      },
    },
  };

  // `SERVER` is a global var injected by my Webpack config to determine SSR
  if (SERVER) {
    opt.defaults = {
      __typename: "State",
      active: SERVER ? true : false, // <-- tests to see if state changes between environments
    } as IState;
  }

  return withClientState(opt);
}

However, the above isn't ideal, since defaults is only available via SSR, and resetting with client.resetStore() means the client has no default state to return to.

Looks like the behavior is defined by these lines

adam-26 commented 5 years ago

An alternative work-around for this that also allows you to have use a defaultState when you reset the store can be utilized following this pattern:

const defaultLinkState = {/*default values here*/};

export default function createClient(initialState) {
  // 1. Create the cache and the apollo link state
  const cache = new InMemoryCache();
  const stateLink = createLinkState(cache, defaultLinkState);

  // 2. AFTER the cache & link state is created, restore the initial state
  if (initialState) {
    cache.restore(initialState);
  }

  return new ApolloClient({
    link: ApolloLink.from([
      stateLink,
      httpLink
    ]),
    cache
  });
}

There are 2 different states to be aware of:

This should be added to the documentation.