Recommended approach for using cached query data in a child component


Out of interest, what would you do in this scenario?

I have a parent component that maps a child component 100s of times.

This child component allows you to change its name we want to check if its name already exists. We have a query available called ‘AllNames’
name: “Some name”

There are few approaches that I could make here, all work fine, but which is the recommended method?

  1. useQuery inside the child component that pulls AllNames. The cache causes this to only run once, despite rendering 100s of components. I then have access to ‘AllNames’ and can check if the inputted name already exists. One annoying part of this method, is that apollo dev tools spams a query for every child component.

  2. useQuery in the PARENT, useQuery in the child with ‘cache-only’ fetch policy (this also spams apollo dev tools)

  3. useQuery in the PARENT component, and the child component uses client.readQuery to pull this query. Same as above, except this way apollo dev tools isn’t spammed with queries.

  4. useQuery in the parent component and pass the existing tools as an array of strings as props to the child components.

Perhaps there isn’t a one-size-fits-all answer to this, e.g. option 1 is probably the most readable as all the logic is in the child components, however this perhaps isn’t best for performance (the fact that dev tools is spammed with queries makes me think this).


If it’s a direct child, I would recommend staying “with React” and just passing things down as props - no need to overengineer things.
Otherwise, you could go for the useFragment hook. I definitely wouldn’t recommend client.readQuery, since that won’t receive any cache updates into your child components in a reactive way.

Thanks for your response!

When you say ‘you could go for the useFragment hook’ - how would this work in this case where the ‘AllNames’ query response types don’t have an ID, even if they did, I thought useFragment can only select a particular Type:ID from the cache?

The only way I could see using useFragment here is if AllNames had a parent query like:

query {
    parent(id: abc) {
        ...SomeFragment containing allNames { ... etc

then useFragment to select SomeFragment with parent id

But I guess each of your names should have an id, and some other properties, too, right?

The way I read your question, each child is representing one name from AllNames - if that’s really just a single string without extra properties, you should definitely pass it as props. If is is a more complex object, the child object should probably have some kind of identifier that you can use with useFragment.

Ah, I see the confusion.

So each child does represent a name - for simplicity sake lets say each name has an id (I just made this whole ‘names’ scenario up to show this concept). We can useFragment as discussed or simply pass props.

BUT each child needs access to ALL names because each child has a ‘Name’ input, that allows the user to modify the name, but it has validation to ensure this name doesn’t already exist.

Passing all names string array as props (or even context if not a direct child) to the child component so it can check if the inputted name already exists would be recommended here over something like useQuery “cache-only” to access all the names in the child?

The problem with useQuery in every of those children would be that you create thousands of cache subscriptions that would all trigger if any name changed. That won’t be a problem dozens or probably even hundreds of times, but might start to become a problem if you get into the thousands.

Tbh., I wouldn’t even pass an array of names down to the children, but a validateName callback or something of the likes. As you describe the children don’t really need to know all the other names, they just need to verify if a new name is valid or not.

1 Like

Perfect, thanks very much - makes much more sense doing it this way :slight_smile: