1

Given below is the query that fetches a list of products and stores it in the apollo-client local cache. It retrieves a list of products and the list of images for every product

const GET_PRODUCTS_QUERY = gql`
  query Products($cursor: String, $query: String, $imageCount: Int = 100) {
    products(first: 9, after: $cursor, query: $query) {
      edges {
        cursor
        node {
          id
          selected @client
          title
          description
          images(first: $imageCount) {
            edges {
              node {
                id
                originalSrc
                selected @client
              }
            }
          }
        }
      }
    }
  }
`;

The data returned is being used to render a UI where the user can select any number of products. I'm using the following mutation to mark a product as selected

(_root, variables, { getCacheKey, cache }) => {
  const id = getCacheKey({
    __typename: "Product",
    id: variables.id
  });
  const fragment = gql`
    fragment toggleSelected on Product {
      selected,
    }
  `;
  const data = cache.readFragment({
    id,
    fragment
  });
  cache.writeData({
    id,
    data: {
      ...data,
      selected: !data.selected
    }
  });

The above mutation is working fine and the selected flag appears on the corresponding product in the cache. Now I have the requirement that when a product is selected, it's first image should also be marked as selected without any manual action from the user. In this case, I do not have the id of the image with me. I just know that whatever be the first image of the selected product, it should be marked as selected. How can I go about achieving this? If I had the id, I guess I will be able to create a fragment on the Image object and get it mutated.

Jophin Joseph
  • 2,864
  • 4
  • 27
  • 40
  • use local resolver returning `true` if undefined earlier? – xadm Feb 10 '20 at 19:49
  • Is `imageCount` constant? If you're ok with hardcoding the value for the `first` argument on `images`, then you can just include that whole field when querying for the fragment. The problem is that the value you provide has to match whatever was used in the original query :/ – Daniel Rearden Feb 10 '20 at 20:49
  • @xadm I'm already doing that to set my initial value. The problem I face is getting the first image of a product so that I can set that also as selected – Jophin Joseph Feb 10 '20 at 23:48
  • @DanielRearden I had tried this, but it did not seem right to use the magic number 100 to retrieve the data. So is this the only viable way to do this? Get all the images with the exact query including the count, get the first image from the returned results, get it's id and then mutate. Is there some other way to do this other than fragments? – Jophin Joseph Feb 10 '20 at 23:51
  • 1
    I'm with you -- I'm not a fan of that approach either :( You can use either fragments or queries, but in either way I suspect we need to know the variable(s) that were used in the original query to pull the correct data out of the cache. The problem boils down to the fact that we need the Image id to mutate it. Is there no way you can get that ID inside the component that calls the mutation and then just pass it in as a variable? – Daniel Rearden Feb 11 '20 at 00:09
  • preselect on every page? useEffect? – xadm Feb 11 '20 at 00:16
  • @DanielRearden I finally went with sending the image id from the component. Even though that component need not be aware of the existence of an image id, I guess this is the only way to do it. Thank you for the help in figuring this out. – Jophin Joseph Feb 11 '20 at 00:38

0 Answers0