'ReactJS useEffect memory leak with chained request

I am making an axios.post request within a useEffect statement. The process is not setting any state, but I am get an Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

I've read about cleanup but it all seems to apply to setting state which I am not doing here. What am I missing?

const CallbackPage = () => {
  const history = useHistory();
  const [getUserAssignments, { data }] = useLazyQuery(GET_USER_AND_ASSIGNMENTS);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    let code = params.get("code");
    let iss = params.get("iss");

    if (params.has("code") && params.has("iss")) {
      axios
        .post(
          `https://login.dts.utah.gov:443/sso/oauth2/access_token?grant_type=authorization_code&client_id=myClientId&code=${code}&iss=${iss}&redirect_uri=http%3A%2%2Flocalhost:4000%2Fcallback`,
          {
            grant_type: "authorization_code",
            code,
            iss,
            redirect_uri: "http://localhost:4000/login/callback",
            client_id: "MyClientId",
            client_secret: "MyClientSecret"
          },
          { headers: { "content-type": "application/x-www-form-urlencoded" } }
        )
        .then((res) => {
          if (res.data.access_token) {
            const decodedToken = jwtDecode(res.data.access_token);
            //get user assignments from GQL database
            getUserAssignments({ variables: { umdId: decodedToken.sub } }).then((response) => {
              if (response.data) {
                sessionStorage.setItem("auth", JSON.stringify(response.data.getUserAndAssignments.assignments));
              }
            });
          }
        })
        .catch((err) => {
          console.log("Error : " + err);
        });
    }
    history.push("/");
  }, [history, getUserAssignments, data]);

  return (
    <Row>
      <Col>
        <em>Redirecting ...</em>
      </Col>
    </Row>
  );
};

export default CallbackPage;


Solution 1:[1]

I maybe wrong but what you are trying is calling async call inside sync call

  const history = useHistory();
  const [getUserAssignments, { data }] = useLazyQuery(GET_USER_AND_ASSIGNMENTS);

  const fetchApi = async () => {
    const params = new URLSearchParams(window.location.search);
    let code = params.get("code");
    let iss = params.get("iss");
    try {
      if (params.has("code") && params.has("iss")) {
        const res = axios.post(
          `https://login.dts.utah.gov:443/sso/oauth2/access_token?grant_type=authorization_code&client_id=myClientId&code=${code}&iss=${iss}&redirect_uri=http%3A%2%2Flocalhost:4000%2Fcallback`,
          {
            grant_type: "authorization_code",
            code,
            iss,
            redirect_uri: "http://localhost:4000/login/callback",
            client_id: "MyClientId",
            client_secret: "MyClientSecret",
          },
          { headers: { "content-type": "application/x-www-form-urlencoded" } }
        );
        if (res.data.access_token) {
          const decodedToken = jwtDecode(res.data.access_token);
          getUserAssignments({
            variables: { umdId: decodedToken.sub },
          });
        }
      }
    } catch (error) {
      console.log("Error : " + error);
    } finally {
      history.push("/");
    }
  };

  useEffect(() => {
    fetchApi();
  }, []);

  useEffect(() => {
    if (data) {
      sessionStorage.setItem(
        "auth",
        JSON.stringify(data.getUserAndAssignments.assignments)
      );
    }
  }, [data]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1