3
votes

I have a nextjs apollo server rendered application using apollo client state. The issue that I'm facing is that on app load, even when the local state is updated correctly, the local state graphql query called in the header component doesn't return the latest state with the correct data, instead it returns the initial state. I am unable to figure out why that is happening and is it because of the apollo client setup or because of the cache initialState.

The app is a nextjs server rendered app using apollo client. I've extensively tried tweaking the apollo client setup to figure out where exactly is the state getting reset [I say reset because on logging the state after updating the state gives me the correct result].

The apollo config is a modified version of the official nextjs apollo example

// lib/apollo.js
...
const appCache = new InMemoryCache().restore(initialState);
const getState = (query) => appCache.readQuery({ query });
const writeState = (state) => appCache.writeData({ data: state });

initCache(appCache);

return new ApolloClient({
  ssrMode: typeof window === 'undefined',
  link: ApolloLink.from([consoleLink, errorLink, authLink, fileUploadLink]),
  cache: appCache,
  resolvers: StateResolvers(getState, writeState),
  typeDefs,
  defaults: {},
  connectToDevTools: true,
});
...
// apollo/StateResolvers.js
export const GET_LOGIN_STATUS_QUERY = gql`
  query {
    loginStatus @client {
      isLoggedIn
    }
  }
`;

export default (getState, writeState) => {
  return {
    Mutation: {
      updateLoginStatus(_, data) {
        const { loginStatus } = getState(GET_LOGIN_STATUS_QUERY);
        const newState = {
          ...loginStatus,
          loginStatus: {
            ...loginStatus,
            ...data,
          },
        };
        writeState(newState);
        const updatedData = getState(terminal); // getting correct updated state here
        console.log('log updateLoginStatus:', updatedData);
        return { ...data, __typename: 'loginStatus' };
      },
    },
  };
};
// initCache.js
export default (appCache) =>
  appCache.writeData({
    data: {
      loginStatus: {
        isLoggedIn: false,
        __typename: 'loginStatus',
      },
    },
  });

Header is imported in the Layout component which is used in the _app.js nextjs file

// header/index.js 
...
const q = gql`
  query {
    loginStatus @client {
      isLoggedIn
    }
  }
`;

const Header = (props) => {
  const { loading, data, error } = useQuery(q); // not getting the updated state here
  console.log('header query data:', loading, data, error);
  return (
    <div>header</div>
  );
};
...

The second log with the result is the output from the checkLoggedIn file similar to the one here

// server side terminal output
log updateLoginStatus: { loginStatus: { isLoggedIn: true, __typename: 'loginStatus' } }
result: { data: updateLoginStatus: { isLoggedIn: true, __typename: 'loginStatus' } } }
header query data: true undefined undefined {}
header query data: false { loginStatus: { isLoggedIn: false, __typename: 'loginStatus' } } undefined
header query data: false { loginStatus: { isLoggedIn: false, __typename: 'loginStatus' } } undefined

My ultimate goal is to get the correctly set isLoggedIn flag in the header to correctly toggle between Logged in and logout state.

Please let me know if any more details are required. Any help would be highly appreciated.

1

1 Answers

1
votes

It looks like you are restoring initial state

You want to restore the server rendered state.

For example:

lets say you did

const state = apolloClient.extract();

return `
<script>
  window.__APOLLO_STATE__ = ${JSON.stringify(state)};
</script>
`;

you want to restore this state

not the inital state