Skip to content

Instantly share code, notes, and snippets.

@simenbrekken
Last active August 7, 2019 15:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simenbrekken/75368a1ee24deb161b8b7b088ca0f714 to your computer and use it in GitHub Desktop.
Save simenbrekken/75368a1ee24deb161b8b7b088ca0f714 to your computer and use it in GitHub Desktop.
Apollo Client 2.0 withFragments

This HoC gives you a way to work with co-located fragments that is similar to Relay's FragmentContainer

It supports both fragment maps extrapolation of prop names from fragment definitions.

Fragment map

export default withFragments({
  price: gql`
    fragment ProductDetails_price on Product {
      id
      price
    }
  `,
})(ProductDetails)

Extrapolating fragment names from AST

export default withFragments(gql`
  fragment ProductDetails_price on Product {
    id
    price
  }
`)(ProductDetails)

Now simply import the fragment into your query:

const ProductQuery = gql`
  query ProductQuery {
    viewer {
      id
    }

    products {
      ...${ProductDetails.fragments.price}
    }
  }
`
import { Component, createElement } from 'react'
import { DOCUMENT, FRAGMENT_DEFINITION } from 'graphql/language/kinds'
import { print } from 'graphql/language/printer'
const inlineFragment = fragment => fragment.replace(/fragment [_A-Za-z][_0-9A-Za-z]*/, '')
const createFragmentMap = fragments => {
const fragmentMap = {}
if (fragments.kind === DOCUMENT) {
fragments.definitions.forEach(definition => {
if (definition.kind === FRAGMENT_DEFINITION) {
const prop = definition.name.value.split('_')[1]
const source = print(definition)
fragmentMap[prop] = inlineFragment(source)
}
})
} else {
Object.keys(fragments).forEach(prop => {
const source = fragments[prop].loc.source.body
fragmentMap[prop] = inlineFragment(source)
})
}
return fragmentMap
}
export default fragments => BaseComponent => {
return class WithFragments extends Component {
static displayName = `withFragment(${BaseComponent.displayName})`
static fragments = createFragmentMap(fragments)
render() {
return createElement(BaseComponent, this.props)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment