Apollo team already provides decent documentation 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.
// 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
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
.
- So this is what we should accept in the inner
In Inner HOC
type WithMutateProps = ChildMutateProps<WithDataProps, CreateUserMutation, CreateUserMutationVariables>;
const withMutate = graphql<WithDataProps, CreateUserMutation, CreateUserMutationVariables, WithMutateProps>
- Accept props
WithDataProps
, passed from the outer HOCwithData
- which already includes
ComponentProps
, so the final props the component consumes is compound of 3: Query data types, Mutation types and component own props.
- which already includes
compose
function?
As of react-apollo version 2.5.2
, compose
is not typed.
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.
Top comments (0)