触发Apollo查询并导致URL更改时useContext中的重新呈现

时间:2020-05-19 15:57:09

标签: javascript graphql next.js apollo-client

GIF of Rerender occuring

我不确定如何继续。如您所见,Header的状态(通过上下文向下传递)正在从用户数据->未定义->同一用户的数据中切换。每次更改网址时都会发生这种情况,当我执行不更改网址的操作时(例如打开购物车),这种情况就不会发生。

这是预期的行为吗?有什么方法可以让我的上下文中的查询仅在没有用户数据或用户数据更改时才被调用?我尝试使用useMemo,但无济于事。

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>
  );
};

(在标头中,userData等于刚刚通过中间组件传递(提供给移动版本)的data)。 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 个答案:

没有答案