apollo-feature-requests icon indicating copy to clipboard operation
apollo-feature-requests copied to clipboard

Provide alternative to subscribeToMore's updateQuery that bypasses merge

Open lorensr opened this issue 5 years ago • 0 comments

My field policy merge is built for pagination and puts things on the end of the list. My objectAdded subscribeToMore should put new things at the beginning of the list. But due to the merge, an updateQuery function returning [newObject, ...prev] (or just [newObject]) results in newObject at the end of the list. I'd like an updateQuery alternative that bypasses the merge, like cache.modify does.

See https://github.com/apollographql/apollo-client/issues/7014 for a similar issue.

Old code

This is what worked before I had a field policy:

  useEffect(() => {
    subscribeToMore({
      document: ON_REVIEW_CREATED_SUBSCRIPTION,
      updateQuery: (prev, { subscriptionData }) => {
        const newReview = subscriptionData.data.reviewCreated
        return {
          reviews: [newReview, ...prev],
        }
      },
    })
  }, [subscribeToMore])

Current workaround

  useEffect(() => {
    subscribeToMore({
      document: ON_REVIEW_CREATED_SUBSCRIPTION,
      updateQuery: (prev, { subscriptionData }) => {
        cache.modify({
          fields: {
            reviews(existingReviewRefs = []) {
              const newReview = subscriptionData.data.reviewCreated
              const newReviewRef = cache.writeFragment({
                data: newReview,
                fragment: gql`
                  fragment NewReview on Review {
                    id
                    text
                    stars
                    createdAt
                    favorited
                    author {
                      id
                    }
                  }
                `,
              })

              return [newReviewRef, ...existingReviewRefs]
            },
          },
        })
        return prev
      },

This gets more complex if there are arguments, as modify is called on all variations of the root query field, vs updateQuery which is just called once for the current argument set.

Proposed API

  useEffect(() => {
    subscribeToMore({
      document: ON_REVIEW_CREATED_SUBSCRIPTION,
      updateCache: (existingRefs = [], { subscriptionData }) => {
        const newReview = subscriptionData.data.reviewCreated
        const newReviewRef = cache.writeFragment({
          data: newReview,
          fragment: gql`
            fragment NewReview on Review {
              id
              text
              stars
              createdAt
              favorited
              author {
                id
              }
            }
          `,
        })

        return [newReviewRef, ...existingReviewRefs]
      },
    })
  }, [subscribeToMore])

Still longer than the old solution, but shorter than the current.

lorensr avatar Nov 01 '20 21:11 lorensr