react-apollo + Codegen + TypeScript, How You Can Compose Multiple Queries/Mutations to a Component
Published: 2019-04-07 05:24:33

---
title: react-apollo + Codegen + TypeScript, How You Can Compose Multiple Queries/Mutations to a Component
published: true
description: 
tags: 
---

Apollo team already provides [decent documentation](https://www.apollographql.com/docs/react/recipes/static-typing) that lets you type your components with types generated from Codegen.

This is a quick tutorial to go further where you compose multiple GraphQL Query/Mutation to bind to a single component.

# Summary

* Define from outer HOCs (e.g. `withData` function) to inner HOCs
* Pass with-data-props to a child HOC
* Do not use `compose()` function

# Example

SUPPOSE this is a new student creation form that requires pulldown schools list. Schools are resolved through GraphQL Query. Also, form submission is done through GraphQL Mutation.

```js
// UserCreate.tsx

import {ChildDataProps, ChildMutateProps} from 'react-apollo';
import {
  CreateUserMutation,
  CreateUserMutationVariables,
} from './__generated__/CreateUserMutation';
import { SchoolsQuery } from './__generated__/SchoolsQuery';
import { CreateUserInput } from "../../../../__generated__/globalTypes";

type ComponentProps = { title: string, };
type WithDataProps = ChildDataProps<ComponentProps, SchoolsQuery, {}>;
const withData = graphql<ComponentProps, SchoolsQuery, {}, WithDataProps>(gql`
  query SchoolsQuery {
    schools {
      id
      email
      nameJa
      nameEn
      phone
    }
  }
`);

type WithMutateProps = ChildMutateProps<WithDataProps, CreateUserMutation, CreateUserMutationVariables>;
const withMutate = graphql<WithDataProps, CreateUserMutation, CreateUserMutationVariables, WithMutateProps>(gql`
  mutation CreateUserMutation($input: CreateUserInput!) {
    createUser(input: $input) {
      email
      nameEn
      nameJa
      school
    }
  }
`);

const UserCreate = withData(withMutate(props => {
  const {
    mutate: createUser,
    data: {schools},
  } = props;
  return (
    <Container>
      <h1>Create New User</h1>
      <Form
        method="post"
        onSubmit={async (e: any) => {
          e.preventDefault();

          const input = (createFormData(e.target) as CreateUserInput ) ;

          const result = await createUser({
            refetchQueries: [
              ({query: UsersQueryGQL} as PureQueryOptions)
            ],
            variables: {input},
          });
          if (!result || !result.data) throw new Error('Mutation failed.');

          const {
            data: {createUser: created},
          } = result;

          // Do something with created user data

          history.push('/users');
        }}
      >
        <FormGroup>
          <Label for="email">User email address:</Label>
          <Input id="email" type="text" name="email"/>
        </FormGroup>

        <FormGroup>
          <Label for="nameJa">User name (Japanese):</Label>
          <Input id="nameJa" type="text" name="nameJa"/>
        </FormGroup>

        <FormGroup>
          <Label for="nameEn">User name (English):</Label>
          <Input id="nameEn" type="text" name="nameEn"/>
        </FormGroup>

        {schools && (
          <>
            <FormGroup>
              <Label for="school">school</Label>
              <p>
                <select id="school" name="school">
                  <option>---please select---</option>
                  {schools.map(s => (
                    <option key={s.id} value={s.id}>
                      {s.nameEn}
                    </option>
                  ))}
                </select>
              </p>
            </FormGroup>
          </>
        )}

        <FormGroup>
          <Button color="primary" type="submit" block>
            Log in
          </Button>
        </FormGroup>
      </Form>
    </Container>
  );
}));

export default UserCreate;
```

# In Outer HOC

```js
type WithDataProps = ChildDataProps<ComponentProps, SchoolsQuery, {}>;
const withData = graphql<ComponentProps, SchoolsQuery, {}, WithDataProps>(/*...*/);
```

* The first argument in generic arguments of `graphql()` is used as actual acceptable properties
* The `WithDataProps` is used as types we pass to the next inner component
    * So this is what we should accept in the inner `withMutate`.

# In Inner HOC

```js
type WithMutateProps = ChildMutateProps<WithDataProps, CreateUserMutation, CreateUserMutationVariables>;
const withMutate = graphql<WithDataProps, CreateUserMutation, CreateUserMutationVariables, WithMutateProps>
```

* Accept props `WithDataProps`, passed from the outer HOC `withData`
    * which already includes `ComponentProps`, so the final props the component consumes is compound of 3: Query data types, Mutation types and component own props.

# `compose` function?

As of react-apollo version `2.5.2`, `compose` is not typed.

```js
export declare function compose(...funcs: Function[]): (...args: any[]) => any;
```

I wrote this post because I couldn't find any example to do that. Hope it helps someone.