Search code examples
javascriptnode.jsreactjsapollogql

How to wait for server response before calling Apollo Graph QL Query?


I'm attempting to call a Graph QL Query after receiving data from my useEffect hook. I need the data from the response to use in the Query. Hooks however cannot be called conditionally. If I take away the condition however, loadedAnime will be undefined. How do I get around this restraint?

import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import AnimeBanner from "../components/AnimeBanner";
import { useHttpClient } from "../Hooks/http-hook";
import { GetAnimeData } from "../GraphQLFunctions";
import { useQuery } from "@apollo/react-hooks";
import gql from "graphql-tag";

const GET_ANIME_INFO = gql`
  query GetAnimeInfo($name: String!) {
    Media(search: $name) {
      title {
        romaji
        english
        native
        userPreferred
      }
      episodes
      id
      bannerImage
    }
  }
`;

const Anime = (props) => {
  //Logic for getting anime data from mongoDB (episodes, name, cover image)
  const { isLoading, error, sendRequest } = useHttpClient();
  const [loadedAnime, setloadedAnime] = useState();
  const URLTitle = useParams().URLTitle;

  useEffect(() => {
    const fetchAnime = async () => {
      try {
        const responseData = await sendRequest(
          "http://localhost:5000/api/anime/" + URLTitle
        );
        setloadedAnime(responseData.animeData[0]);
      } catch (err) {
        console.log(err);
      }
    };
    fetchAnime();
  }, [sendRequest, URLTitle]);

  if (isLoading || error) {
    return null;
  }

  //Logic for getting anime data from anilist (Descriptions, tags, banner, trailer, etc.)
  const { apiData, apiLoading, apiError } = useQuery(GET_ANIME_INFO, {
    variables: {
      name: loadedAnime.anime_name,
    },
  });

  if (apiLoading || apiError) {
    return null;
  }

  return <AnimeBanner src={apiData.Media.bannerImage} />;
};

export default Anime;


Solution

  • Short Answer: You can checkout useLazyQuery instead of useQuery.

    Documentation link: https://www.apollographql.com/docs/react/data/queries/#executing-queries-manually


    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

    import React, { useState } from 'react';
    import { useLazyQuery } from '@apollo/client';
    
    function DelayedQuery() {
      const [dog, setDog] = useState(null);
      const [getDog, { loading, data }] = useLazyQuery(GET_DOG_PHOTO);
    
      if (loading) return <p>Loading ...</p>;
    
      if (data && data.dog) {
        setDog(data.dog);
      }
    
      return (
        <div>
          {dog && <img src={dog.displayImage} />}
          <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>
            Click me!
          </button>
        </div>
      );
    }