Apollo Queries triggered and causing rerendering in useContext on URL Change

Viewed 768

GIF of Rerender occuring

I'm not sure how to proceed. As you can see, the Header's state (as passed down via context) is switching from the user's data --> undefined --> same user's data. This occurs every time there's a url change, and doesn't happen when I do things that don't change the url (like opening the cart for example).

Is this expected behaviour? Is there any way I can get the query in my context to only be called when there is no user data or when the user data changes? I tried using useMemo, but to no avail.

auth.context

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

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

export const AuthProvider = ({ children }) => {
  const [customer, { data, loading, error }] = useLazyQuery(
    GET_LOGGED_IN_CUSTOMER,
    {
      ssr: true,
    }
  );

  const { data: auth } = useQuery(CURRENT_USER, {
    onCompleted: (auth) => {
      console.log(auth);
      customer({
        variables: {
          where: {
            id: auth.currentUser.id,
          },
        },
      });
    },
    ssr: true,
  });
  console.log(data);

  const isValidToken = () => {
    if (isBrowser && data) {
      const token = localStorage.getItem("token");
      if (error) {
        console.log("error", error);
      }
      if (token && data) {
        console.log("token + auth");
        return true;
      } else return false;
    }
  };
  const [isAuthenticated, makeAuthenticated] = useState(isValidToken());
  function authenticate() {
    makeAuthenticated(isValidToken());
  }
  function signout() {
    makeAuthenticated(false);
    localStorage.removeItem("token");
  }
  return (
    <AuthContext.Provider
      value={{
        isAuthenticated,
        data,
        authenticate,
        auth,
        signout,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

(In Header, userData is equal to data just passed through an intermediary component (to provide to mobile version)). header.tsx

import React, { useContext } from "react";
import Router, { useRouter } from "next/router";
import { useApolloClient } from "@apollo/client";
import { openModal } from "@redq/reuse-modal";
import SearchBox from "components/SearchBox/SearchBox";
import { SearchContext } from "contexts/search/search.context";
import { AuthContext } from "contexts/auth/auth.context";
import LoginModal from "containers/LoginModal";
import { RightMenu } from "./Menu/RightMenu/RightMenu";
import { LeftMenu } from "./Menu/LeftMenu/LeftMenu";
import HeaderWrapper from "./Header.style";
import LogoImage from "image/hatchli-reduced-logo.svg";
import { isCategoryPage } from "../is-home-page";

type Props = {
  className?: string;
  token?: string;
  pathname?: string;
  userData?: any;
};

const Header: React.FC<Props> = ({ className, userData }) => {
  const client = useApolloClient();
  const { isAuthenticated, signout } = useContext<any>(AuthContext);
  const { state, dispatch } = useContext(SearchContext);
  console.log(isAuthenticated);
  console.log(userData);

  const { pathname, query } = useRouter();
  const handleLogout = () => {
    if (typeof window !== "undefined") {
      signout();
      client.resetStore();
      Router.push("/medicine");
    }
  };

  const handleJoin = () => {
    openModal({
      config: {
        className: "login-modal",
        disableDragging: true,
        width: "auto",
        height: "auto",
        animationFrom: { transform: "translateY(100px)" },
        animationTo: { transform: "translateY(0)" },
        transition: {
          mass: 1,
          tension: 180,
          friction: 26,
        },
      },
      component: LoginModal,
      componentProps: {},
      closeComponent: "",
      closeOnClickOutside: true,
    });
  };
  const onSearch = (text: any) => {
    dispatch({
      type: "UPDATE",
      payload: {
        ...state,
        text,
      },
    });
  };

  const { text } = state;
  const onClickHandler = () => {
    const updatedQuery = query.category
      ? { text: text, category: query.category }
      : { text };
    Router.push({
      pathname: pathname,
      query: updatedQuery,
    });
  };
  const showSearch = isCategoryPage(pathname);

  return (
    <HeaderWrapper className={className}>
      <LeftMenu logo={LogoImage} />
      {showSearch && (
        <SearchBox
          className="headerSearch"
          handleSearch={(value: any) => onSearch(value)}
          onClick={onClickHandler}
          placeholder="Search anything..."
          hideType={true}
          minimal={true}
          showSvg={true}
          style={{ width: "100%" }}
          value={text || ""}
        />
      )}
      <RightMenu
        isAuth={userData}
        onJoin={handleJoin}
        onLogout={handleLogout}
        avatar={userData && userData.user && userData.user.avatar}
      />
    </HeaderWrapper>
  );
};

export default Header;

0 Answers
Related