Search code examples
reactjsgraphqlapollo

How to use detalization queries in apollo graphql reactjs?


Suppose data - is data from a parent query.

Child react-component:

const ShowDetails = ({data}) => {
   const { loading, error, data_details } = useQuery(someQueryAsksAdditionalFileldsForEntryAlreadyPresentInCache);
}

someQueryAsksAdditionalFileldsForEntryAlreadyPresentInCache -- asks for additional fields that are missing in data.

When (!loading && !error) data_details will have requested fields.

Issue: data_details will have only requested fields.

Question: Is there a way to use parent data with merged-additional-requested fields in ShowDetails and ignore data_details?

In Chrome with help of Apollo devtools I see that apollo-cache has one entry from merged data and data_details.

I do not want to re-fetch all existed entries in data.

Example:

Parent component query:

const bookQuery = gql`
  query ($bookId: ID!) {
    book(id: $bookId) {
      id
      author
    }
  }
`

Details query:

const bookEditionsQuery = gql`
  query ($bookId: ID!) {
    book(id: $bookId) {
      id
      editions {
        publisher
        year
      }
    }
  }
`
const bookReviewQuery = gql`
  query ($bookId: ID!) {
    book(id: $bookId) {
      id
      review {
        user
        score
        date
      }
    }
  }
`

All this queries will populate the same bucket in Apollo cache: book with id.

What is necessary to achieve: in react component BookDetails:

have 1 object with:

data.author data.editions[0].year data.review[0].user

Logically - this is one entry in cache.

Thank you for your help.


Solution

  • Almost nothing to save by using already fetched [and passed from parent] data ... only author ... all review and edition must be fetched, no cache usage at all.

    ... fetching review and editions by book resolver helps apollo cache to keep relation but also requires API to use additional ('book') resolver [level] while it is not required ... review and editions resolvers should be callable directly with book id ... and f.e. can be used by separate <Review /> sub component ... or review and editions called within one request using the same id parameter.

    Just use data and dataDetails separately in component - avoid code complications, keep it simply readable:

    const ShowDetails = ({data}) => {
       const { loading, error, data:dataDetails } = useQuery(someQueryAsksAdditionalFileldsForEntryAlreadyPresentInCache);
    }
    if(loading) return "loading...";
    return (
      <div>
        <div>author: {data.author}</div>
        {dataDetails.review.map(...
    

    ... if you really want to join data

    const ShowDetails = ({data}) => {
       const [bookData, setBookData] = useState(null);
       const { loading, error, data:dataDetails } = useQuery(someQueryAsksAdditionalFileldsForEntryAlreadyPresentInCache, {
        onCompleted: (newData) => {
            setBookData( {...data, ...newData } );
          }
        });
        if(bookData) return ...
          // {bookData.author}
          // bookData.review.map(...