How to get one element from a query that gets all elements?

I’m working with Apollo Client and React.

The question is how to make Apollo realise that getClass is looking for one element into the result of getClasses.

For example, I have a list of all classes that getClasses return, then when the user clicks on the link it shows the data of that class (ShowDetails). The problem is that right now Apollo is making another httpRequest to fetch the data that is already in the cache.

Of course, that I can pass the data with props, but I want the child component to be independent of the parent. If the user access directly to the ShowDetails I need to make a request, but if he access using the link I want to use the cached data.

This makes sense or I missing something ?

const CLASS_FRAGMENT = gql`
    fragment ClassFields on Class {
        id
        date
        hour
        name
        activity
    }
`;

export const GET_ALL_CLASSES = gql`
    ${CLASS_FRAGMENT}
    query getClasses {
        classes {
            ...ClassFields
        }
    }
`;

export const GET_CLASS = gql`
    ${CLASS_FRAGMENT}
    query getClass($id: ID!) {
        getClasses(id: $id) {
            ...ClassFields
        }
    }
`;

This is the configuration for Apollo Client

const cache = new InMemoryCache({
    typePolicies: {
        Query: {
            fields: {
                groups: {
                    merge(existing = [], incoming) {
                        return incoming;
                    },
                },
                classes: {
                    merge(existing = [], incoming) {
                        return incoming;
                    },
                },
                students: {
                    merge(existing = [], incoming) {
                        return incoming;
                    },
                },
                payments: {
                    merge(existing = [], incoming) {
                        return incoming;
                    },
                },
            },
        },
        Group: {
            keyFields: ["id"],
        },
        Class: {
            keyFields: ["id"],
        },
        Affiliate: {
            keyFields: ["id"],
        },
        Payment: {
            keyField: ["id"],
        },
    },
});

export const useApolloClient = () => {
    return new ApolloClient({
        link: from([errorLink, httpLink]),
        cache,
    });
};

Thanks!

The problem is that Apollo doesn’t know that your GET_CLASS query will return an item that is already in the cache. The GET_CLASS and GET_CLASSES query results are stored separately in the cache and before performing a server request there is no way for Apollo to know that they are related. My suggestion would in fact be to pass the class as a prop to the component, but if you really don’t want to (or can’t) do this, you could just use the GET_CLASSES query in the child components, which will cause a cache hit, and then you’d just pick the class object you need out of the result array.

1 Like

@Mauric the Cache redirects using field policy read functions section of the docs might help as well. It shows an example of how to wire up a list/detail view, re-using the previously fetched data without firing another network request.

3 Likes

This is probably the better way. You should do that instead. :slight_smile:

Thanks! It works as expected!

1 Like

Solved.