Unnecessary rerenders using Apollo + useContext for Authentication (SSR)

Viewed 403

I'm experiencing rerenders seemingly as a result of useQuery being called when I don't want it to be.

First load, isAuthenticated's state is instantiated via a function that makes a query to the server to get the userId based on the attached header. If a valid header is present, isAuthenticated is set to true and therefore useMemo is called (as isAuthenticated is a dependency). useMemo calls setUser, which puts the userId and role into the context, to be passed down through the AuthProvider (in _app, wrapping everything but the ApolloProvider).

I use the userId in the Navbar (via useContext) to get the avatar (and other things in the rest of the app). What I've noticed is that any time I click on something (for example, a separate query filtering products), the CURRENT_USER query in _app is called. And this manifests as the Navbar losing the useId data passed to it for a second, and then reverts back. So, everytime I click on things, my Navbar is rerendering. I don't understand why the CURRENT_USER query keeps being called...

For context, I use the same setup in another app that does not have SSR without issue.

auth.context.js

import React, { useState, useEffect, useMemo} from "react";
import { CURRENT_USER } from "graphql/query/customer.query";
import { gql, useQuery } from "@apollo/client";
import { isBrowser } from "components/helpers/isBrowser";

export const AuthContext = React.createContext({});

export const AuthProvider = ({ children }) => {
  const { data, error, loading } = useQuery(CURRENT_USER, {
    onCompleted: () => {
      console.log("called query", data);
    },
    ssr: true,
  });
  const isValidToken = () => {
    if (isBrowser) {
      const token = localStorage.getItem("token");
      if (error) {
        return false;
      }
      if (!loading && !data) {
        return false;
      }
      if (token && data?.currentUser) {
        console.log(data.currentUser);
        return true;
      }
      if (!token) {
        return false;
      }
    }
  };
  const [isAuthenticated, makeAuthenticated] = useState(isValidToken());
  const [user, setUser] = useState({});
  function authenticate() {
    console.log(isAuthenticated);
    makeAuthenticated(isValidToken());
  }
  useEffect(() => {
    console.log("attempted to run");
    if (data && isAuthenticated) {
      setUser(data.currentUser);
      console.log("user", user);
    }
  }, [isAuthenticated]);
  function signout() {
    makeAuthenticated(false);
    localStorage.removeItem("token");
  }
  return (
    <AuthContext.Provider
      value={{
        isAuthenticated,
        authenticate,
        signout,
        user,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

"@apollo/client": "^3.0.0-beta.44",

"next": "^9.3.6",

"react": "^16.13.1",

0 Answers
Related