react-apollo@3.0.0へ移行する
現在のステータスはbetaですので、急ぐ必要はないです。
$ npm i react-apollo@beta
大きな注目点としては、hooksの追加と@apollo/react-testing
への分離でしょうか。
この記事は、自分がぶつかった部分のまとめなので抜けはあります、注意してください。
Entry Point
内部的な話ですが、すべて名前空間にパッケージが移され、react-apollo自体は後方互換のためのプロキシとなります。
react-apolloのentryは以下のようになります。
// index.js export { getApolloContext, resetApolloContext, ApolloProvider, ApolloConsumer } from '@apollo/react-common'; export { Query, Mutation, Subscription } from '@apollo/react-components'; export { graphql, withQuery, withMutation, withSubscription, withApollo } from '@apollo/react-hoc'; export { useQuery, useMutation, useSubscription, useApolloClient, getMarkupFromTree, getDataFromTree, renderToStringWithData } from '@apollo/react-hooks'; //# sourceMappingURL=index.js.map
Hooks
react-hooksの登場に伴って、apolloも今後はhooksが主流になっていきます。
QueryとMutationは以下のような書き方に変更できます。
// スキーマ const GET_ORGS = gql` query { organizations { name uid } } `; const ADD_ORG = gql` mutation addOrganization($name: String!) { addOrganization(name: $name) { name uri uid } } `;
以前のクラス
// ここでdataの型を今までは入れないと推論ができなかった class GetOrgsQuery extends Query<{ organizations: Organizations }> {} export class OrganizationsBox extends React.PureComponent<unknown, State> { state = { currentValue: '' }; onChange = (e: React.FormEvent<HTMLInputElement>) => { this.setState({ currentValue: e.currentTarget.value }); }; onSubmit = (addOrganization: MutationFunc) => { addOrganization({ variables: { name: this.state.currentValue } }); this.setState({ currentValue: '' }); }; render() { return ( <GetOrgsQuery query={GET_ORGS}> {({ loading, error, data }) => ( <Ul> {error || loading ? <p>{error ? `Error! ${error.message}` : 'loading...'}</p> : null} {data && data.organizations && data.organizations.map(({ name, uid }) => ( <Li key={uid}> <A to={`/orgs/${name}`}>{name}</A> </Li> ))} <Mutation mutation={ADD_ORG} refetchQueries={[{ query: GET_ORGS }]}> {(addOrganization, { error }) => ( <React.Fragment> {error && <p>{`Error! ${error.message}`}</p>} <InputBox> <input onChange={this.onChange} value={this.state.currentValue} /> <button onClick={() => this.onSubmit(addOrganization)}>Add</button> </InputBox> </React.Fragment> )} </Mutation> </Ul> )} </GetOrgsQuery> ); } }
Hooks
import { useQuery, useMutation } from 'react-apollo'; export const OrganizationsBox: React.FC = () => { const [currentValue, updateCurrentValue] = useState(''); const { loading, error, data } = useQuery<{ organizations: Organizations }>(GET_ORGS); const [addOrganization, { error, data }] = useMutation(ADD_ORG, { refetchQueries: [{ query: GET_ORGS }] }); const onChange = (e: React.FormEvent<HTMLInputElement>) => { updateCurrentValue(e.currentTarget.value); }; const onSubmit = (addOrganization: any) => { addOrganization({ variables: { name: currentValue } }); updateCurrentValue(''); }; if (error || loading) { return <p>{error ? `Error! ${error.message}` : 'loading...'}</p>; } return ( <Ul> {data && data.organizations.map(({ name, uid }) => ( <Li key={uid}> <A to={`/orgs/${name}`}>{name}</A> </Li> ))} <InputBox> <input onChange={onChange} value={currentValue} /> <button onClick={() => onSubmit(addOrganization)}>Add</button> </InputBox> </Ul> ); };
上記の通り、jsx内で関数を書く必要がなくなり、可読性が増しました。
const { loading, error, data } = useQuery(GET_ORGS); const [addOrganization, { error, data }] = useMutation(ADD_ORG); const { loading, data } = useSubscription(LATEST_ORGS);
と定義し、コールすれば終わりです。
注意点として、Mutationだけユーザー定義が入るため配列です。
react-testing
よくテストやstorybookで使われる MockedProvider
はreact-apollo
からのインポートではなく、@apollo-react-testing
というライブラリからのインポートに変更されます。
- import { MockedProvider } from 'react-apollo/test-utils'; + import { MockedProvider } from '@apollo/react-testing';
MockLink
, MockSubscriptionLink
も同様に移動しました。
型定義
リネーム
MutationFn
が MutationFunction
に中身は同様でリネームされました。
削除
自分が把握している限りで以下の型がなくなりました。
GraphqlQueryControls
、MutationFunc
、ChildDataProps
独自で定義する場合は以下のようになります。
import { OperationVariables, QueryControls, MutationFunction, DataProps } from 'react-apollo'; export interface GraphqlQueryControls<TGraphQLVariables = OperationVariables> extends QueryControls<any, TGraphQLVariables> {} export type MutationFunc<TData = any, TVariables = OperationVariables> = MutationFunction< TData, TVariables >; export type ChildDataProps< TProps = {}, TData = {}, TGraphQLVariables = OperationVariables > = TProps & DataProps<TData, TGraphQLVariables>;
その他
walkTree
のサポートが無くなる- preactのサポートがなくなる
compose
もなくなる- 中身がlodashの
flowRight
と同じなので各自で定義してねとのこと
- 中身がlodashの
昔から思っていた不満がどんどんなくなってきていて、最高になってきているので今後も楽しみ。