javedb
javedb

Reputation: 228

How to useQuery on props change with Apollo?

Currently I have a BooksList component and I'm passing down props to my BooksDetails component when a title is clicked. How do I use an Apollo hook to only query on props change?

I'm not sure how to do this using hooks. I've looked through the UseQuery documentation from Apollo. I couldn't find documentation on UseLazyQuery.

I've tried the following, but it always returns undefined:

const { loading, error, data } = useQuery(getBookQuery, {
    options: (props) => {
      return {
        variables: {
          id: props.bookId
        }
      }
    }
  })

BookList:

const BookList = () => {
  const {loading, error, data} = useQuery(getBooksQuery)
  const [selectedId, setId] = useState('');


  return (
    <div id='main'>
      <ul id='book-list'>
        {data && data.books.map(book => (
          <li onClick={() => setId(book.id)} key={book.id}>{book.name}</li>
        )) }
      </ul>
      <BookDetails bookId={selectedId} />
    </div>
  );
};

export default BookList;

BookDetails:

const BookDetails = (props) => {

  const { loading, error, data } = useQuery(getBookQuery, {
    options: (props) => {
      return {
        variables: {
          id: props.bookId
        }
      }
    }
  })

  console.log(data)
  return (
    <div id='book-details'>
      <p>Output Book Details here</p>
    </div>
  );
};

export default BookDetails;

EDIT - I forgot to add that my GetBookQuery has a parameter of ID so an example would be getBookQuery(123).

Upvotes: 5

Views: 4137

Answers (2)

Dhaval L.
Dhaval L.

Reputation: 657

I was also following along the same example and I came up here with the same question. I tried doing the following way. This might be helpful for someone.

BookDetails.js:

function BookDetails({ bookId }) {
  const [loadDetails, { loading, error, data }] = useLazyQuery(getBook);

  useEffect(() => {
    if (bookId) {
      loadDetails({ variables: { id: bookId } });
    }
  }, [bookId, loadDetails]);

  if (!bookId) return null;
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  // for example purpose
  return <div>{JSON.stringify(data)}</div>;
}

export default BookDetails;

Upvotes: 2

Bassem
Bassem

Reputation: 4030

Use the useLazyQuery like this instead:

  const [getBook, { loading, error, data }] = useLazyQuery(getBooksQuery);

Full example:

import React from 'react';
import { useLazyQuery } from '@apollo/react-hooks';

const BookList = () => {
    const [getBook, { loading, error, data }] = useLazyQuery(getBooksQuery);

  return (
    <div id='main'>
      <ul id='book-list'>
        {data && data.books.map(book => (
          <li onClick={() => getBook({ variables: { id: book.id } })}} key={book.id}>{book.name}</li>
        )) }
      </ul>
      <BookDetails data={data} />
    </div>
  );
};

export default BookList;

Examples and documentation can be found in Apollo's GraphQL documentation https://www.apollographql.com/docs/react/data/queries/

Upvotes: 7

Related Questions