React apollo client api calling two time

Viewed 1403

This is my React code of ApolloClient

function EmpTable() {      
  const GET_EMPLOYEE = gql`
    query refetch($id: String) {
      employeeById(id: $id) {
        id
        name
        role
      }
    }
  `;

  const {refetch} = useQuery(GET_EMPLOYEE)

  const getEmpByID = (id) => {
    refetch({
      id: id
    }).then((response) => {
      // do something
    })
    
  }

  return (
    <div className="row">
      {/* { I am rending list of employee with map and passing id this way
         <a onClick={() => getEmpByID(id)}>get employ info</a>
      } */}    
    </div>
  );
}

export default EmpTable;

Everything is working very well in this code, the only problem is the API being called two times, first time it returns no data, and 2nd time, it returns the expected data.

How can I prevent calling this twice?

I guess this is executing first time: const {refetch} = useQuery(GET_EMPLOYEE) and making the first request without data, because, no variable is passed there. I know I can can pass a variable in useQuery first time but the problem is that I can’t pass this from there, because the query params are not in my state or props.

Can anyone tell me what is the possible solution for this?

2 Answers

Due to documentantion:

When React mounts and renders a component that calls the useQuery hook, Apollo Client automatically executes the specified query. But what if you want to execute a query in response to a different event, such as a user clicking a button? The useLazyQuery hook is perfect for executing queries in response to events other than component rendering. This hook acts just like useQuery, with one key exception: when useLazyQuery is called, it does not immediately execute its associated query. Instead, it returns a function in its result tuple that you can call whenever you're ready to execute the query:

Example :

const GET_COUNTRIES = gql`
  {
    countries {
      code
      name
    }
  }
`;
export function DelayedCountries() {
  const [getCountries, { loading, data }] = useLazyQuery(GET_COUNTRIES);
  if (loading) return <p>Loading ...</p>;

  if (data && data.countries) {
    console.log(data.countries);
  }

  return (
    <div>
      <button onClick={() => getCountries()}>
        Click me to print all countries!
      </button>
      {data &&
        data.countries &&
        data.countries.map((c, i) => <div key={i}>{c.name}</div>)}
    </div>
  );
}

useLazyQuery will be executed at the moment, when getCountries is called.

https://codesandbox.io/s/apollo-client-uselazyquery-example-6ui35?file=/src/Countries.js

This is a normal behavior in React 18, all events are called twice, this is new in React 18, and, only happens in development.

Now, why are they doing this? because it helps to identify bugged effects and hooks, and it works.

If you wanna disable this you can do it by disabling strict mode (https://reactjs.org/docs/strict-mode.html).

So, if the component is working, you have no warning about data leaking stay calm and continue. Another option to try is compile your application and run it in production mode, if the hook it's called twice then yeah, by all means, validate your component code (and it's parent components)

Related