Last active
March 7, 2018 13:25
-
-
Save danielkcz/655d562e7fd72fd5fa791042fda008c7 to your computer and use it in GitHub Desktop.
Apollo GraphQL with render props
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ApolloQueryResult } from 'apollo-client' | |
import { DocumentNode } from 'graphql' | |
import React from 'react' | |
import { graphql } from 'react-apollo' | |
import { MutationFunc, MutationOpts } from 'react-apollo/types' | |
interface IQueryProps<TResult, TVariables = {}> { | |
render( | |
execute: (variables?: Partial<TVariables>) => Promise<TResult>, | |
executionOptions?: MutationOpts<TVariables>, | |
): ReactNode | |
variables?: Partial<TVariables> | |
} | |
type ChildProps<TResult> = { | |
mutate: MutationFunc<TResult> | |
} | |
export function buildMutation<TResult, TVariables = {}>( | |
document: DocumentNode, | |
getOptions: ( | |
variables: Partial<TVariables>, | |
) => MutationOpts<TVariables> = () => ({}), | |
) { | |
const Mutation: React.SFC< | |
ChildProps<TResult> & IQueryProps<TResult, TVariables> | |
> = ({ mutate, render }) => { | |
async function execute( | |
variables: Partial<TVariables> = {}, | |
executionOptions: MutationOpts<TVariables> = {}, | |
) { | |
const result: ApolloQueryResult<TResult> = await mutate({ | |
variables, | |
...executionOptions, | |
}) | |
return result.data | |
} | |
return render(execute) | |
} | |
const options = (props: IQueryProps<TResult, TVariables>) => { | |
return { | |
variables: props.variables, | |
...getOptions(props.variables || {}), | |
} | |
} | |
const wrapper = graphql<TResult, IQueryProps<TResult, TVariables>>(document, { | |
options, | |
}) | |
return wrapper(Mutation) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { DocumentNode } from 'graphql' | |
import React from 'react' | |
import { graphql } from 'react-apollo' | |
import { QueryProps } from 'react-apollo/types' | |
import { Loading } from '../atoms/Loading' | |
interface IQueryProps<TResult, TVariables = {}> { | |
render?(data: TResult): ReactNode | |
renderList?(data: TResult): ReactNode[] | |
renderLoading?(): ReactNode | |
skip?: boolean | |
variables?: TVariables | |
} | |
type ChildProps<TResult> = { | |
data: QueryProps & TResult | |
} | |
export function buildQuery<TResult, TVariables = {}>(document: DocumentNode) { | |
const Query: React.SFC< | |
ChildProps<TResult> & IQueryProps<TResult, TVariables> | |
> = ({ | |
data, | |
render, | |
renderList, | |
renderLoading = () => <Loading />, | |
skip = false, | |
}) => { | |
if (skip === true || !data) { | |
return null | |
} | |
if (data.loading) { | |
return renderLoading() | |
} | |
const result: TResult = data | |
if (renderList) { | |
return <>{renderList(result)}</> | |
} | |
if (render) { | |
return render(result) | |
} | |
return null | |
} | |
const options = (props: IQueryProps<TResult, TVariables>) => { | |
return { | |
skip: props.skip, | |
variables: props.variables, | |
} | |
} | |
const wrapper = graphql<TResult, IQueryProps<TResult, TVariables>>(document, { | |
options, | |
}) | |
return wrapper(Query) | |
} |
Another example of a use for mutations. I am aware it's still a bit simplified as I building it based on my needs, but it's working quite well.
function VisibilityToggleButton({ ware }: { ware: GWareList.Wares }) {
return (
<WareListVisibilityMutation
variables={{
wareId: ware.id,
}}
render={updateVisibility => (
<VisibilityButton
isVisible={ware.enabled}
onClick={() => updateVisibility({
visibility: !ware.enabled,
})}
/>
)}
/>
)
}
Defining such mutation looks very similar to queries.
import { buildMutation } from '@graph/buildMutation'
import { GWareListVisibility } from '@typings/types'
import gql from 'graphql-tag'
export const WareListVisibilityMutation = buildMutation<
GWareListVisibility.Mutation,
GWareListVisibility.Variables
>(gql`
mutation GWareListVisibility($wareId: ID!, $visibility: Boolean!) {
updateWare(id: $wareId, ware: { enabled: $visibility }) {
id
enabled
}
}
`)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TypeScript is obviously optional here, but it helps a big time. For example, I have a file with a query like this.
I am using graphql-code-generator and resulting typescript definition may look like this. I just write a query first (with help of snippets), execute generator and then I have a fully typed experience when working with the data.
Finally I can use that Query component simply like this.