Skip to content

Instantly share code, notes, and snippets.

@simenbrekken
Last active August 7, 2019 15:01
Show Gist options
  • Select an option

  • Save simenbrekken/75368a1ee24deb161b8b7b088ca0f714 to your computer and use it in GitHub Desktop.

Select an option

Save simenbrekken/75368a1ee24deb161b8b7b088ca0f714 to your computer and use it in GitHub Desktop.

Revisions

  1. simenbrekken revised this gist Nov 22, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -40,4 +40,5 @@ const ProductQuery = gql`
    ...${ProductDetails.fragments.price}
    }
    }
    `
    ```
  2. simenbrekken created this gist Nov 22, 2017.
    43 changes: 43 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    This HoC gives you a way to work with co-located fragments that is similar to [Relay's FragmentContainer](https://facebook.github.io/relay/docs/fragment-container.html)

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

    **Fragment map**

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

    **Extrapolating fragment names from AST**

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

    ```

    Now simply import the fragment into your query:

    ```js
    const ProductQuery = gql`
    query ProductQuery {
    viewer {
    id
    }
    products {
    ...${ProductDetails.fragments.price}
    }
    }
    ```
    39 changes: 39 additions & 0 deletions withFragments.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    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)
    }
    }
    }