Search code examples
javascriptreactjsreact-hooksapollo

Infinite loop when using useLazyQuery in React + Apollo/GraphQL?


My code so far looks something like this:

const { ID } = useParams();
const [getObjects, {loading, data}] = useLazyQuery(GET_OBJECTS_BY_ID);

const objectWithID = props.data.find(datum => datum._id == ID);
if (objectWithID.conditional) {
    getObjects({variables: {objectIds: objectWithID.subObjects}});
    //Do a bunch of other stuff including a separate render
}
else {...}

What I'm essentially doing is finding an object with the specified ID first, and then querying for its subObjects. I want to first find the objectWithID variable before querying, and then based on one of its parameters, conditionally use its value, hence I think useLazyQuery helps to achieve this. However, this causes an infinite loop: for some reason it's being called an infinite number of times, crashing my webpage. Am I using useLazyQuery incorrectly? How could I prevent this infinite loop?


Solution

  • In this case, you're executing the query inside the render method, meaning it'll just keep firing. Instead, consider using a useEffect hook:

    const { ID } = useParams();
    const [getObjects, { loading, data }] = useLazyQuery(GET_OBJECTS_BY_ID);
    
    const objectWithID = useMemo(() => {
      return props.data.find((datum) => datum._id == ID);
    }, [props.data, ID]);
    
    useEffect(() => {
      if (objectWithID.conditional) {
        getObjects({ variables: { objectIds: objectWithID.subObjects } });
      }
    }, [getObjects, objectWithID]);
    
    return objectWithID.conditional ? (
      <>Render one thing</>
    ) : (
      <>Render the other thing</>
    );
    

    Note that I also threw in a useMemo hook to memoize the objectWithID value so it only changes when props.data or ID changes.