Hongli Bu
Hongli Bu

Reputation: 159

why polling of Apollo useQuery don't call onCompleted?

I am playing around the code: https://codesandbox.io/s/restless-framework-uldf4q?file=/src/App.js

import React, { Fragment } from "react";
import { gql } from "apollo-boost";
import { useQuery } from "@apollo/react-hooks";

const GET_DOG_PHOTO = gql`
  query Dog($breed: String!) {
    dog(breed: $breed) {
      id
      displayImage
    }
  }
`;

const breed = "dingo";

const App = () => {
  const [count, setCount] = React.useState(0);
  const { loading, error, data, startPolling, stopPolling } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      onCompleted: () => {
        setCount((count) => count + 1);
      }
    }
  );

  if (loading) {
    return <h2>loading</h2>;
  }
  if (error) {
    return <h2>Whoops</h2>;
  }

  return (
    <div>
      <h1> {count}</h1>
      <Fragment>
        <img
          alt="Cute Doggo"
          src={data.dog.displayImage}
          style={{ height: 500, width: 500 }}
        />
        <button onClick={() =>startPolling(500)}>Start</button>
        <button onClick={stopPolling}>Stop</button>
      </Fragment>
    </div>
  );
};

export default App;

In my code, I setCount to count+1 using React.useState in the onCompleted callback? why it just stop counting when polling?

so what is the mechanism here?

Upvotes: 2

Views: 1153

Answers (3)

Aaron Ong
Aaron Ong

Reputation: 221

As of Apollo 3.8+, onCompleted only gets called when notifyOnNetworkStatusChange is set to true. However, this is not ideal because it calls onCompleted several times per second, regardless of the pollInterval that you set. You're better off placing the contents of onCompleted in a useEffect(), with data as a dependency.

const { loading, error, data, startPolling, stopPolling } = useQuery(
  GET_DOG_PHOTO,
  {
    variables: { breed }
  }
);

useEffect(() => {
  setCount((count) => count + 1);
}, [data]);

Upvotes: 1

Pulkit Aggarwal
Pulkit Aggarwal

Reputation: 2672

You can also use notifyOnNetworkStatusChange option as true. It will change the loading state as well every time.

Call api as

const { loading, error, data, startPolling, stopPolling } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      notifyOnNetworkStatusChange: true,
      onCompleted: () => {
        setCount((count) => count + 1);
      }
    }
  );

Upvotes: 2

Jonathan Wieben
Jonathan Wieben

Reputation: 671

I can also observe that the onCompleted callback is not invoked as expected in the reproducer you provide.

In your CodeSandbox, you are using a 3-year-old deprecated version of the useQuery hook. You could migrate to the latest @apollo/client package, which will solve the issue.

See this migrated CodeSandbox: https://codesandbox.io/s/apolllo-on-completed-n9wzge

Upvotes: 2

Related Questions