はじめに
GraphQLを用いたフロントエンド開発は多くなってきているように思います。
フロントエンドから柔軟にデータを取ってくることができるということは、今までバックエンドが担保してきていた部分をフロントエンドが担わないといけなくなった
ということを意味します。
保守性をちゃんと考えないといけない。
ということですね。
今回は、Fragmentについての話
Fragmentとは?
GraphQLにおけるFragmentとは複雑なクエリを小さくまとめ上げるために生み出されました。
これはとてもComponentの概念に似ていますね。
僕たちはComponentという小さな単位に分割し、それを組み合わせることで複雑なアプリケーションを構築しています。
これと同じです。
データをFragmentという小さな単位に分割し、複雑なクエリを役割ごとに分割してやろう。
という話です。
どうやって実現する?
親コンポーネントで子コンポーネントを呼び出すのと同じように、親のクエリで子のfragmentを呼び出します。
fragment UserFragment on User {
name
age
profile_picture(scale: 2) {
uri
}
}
query UserQuery($id: ID!) {
user(id: $id) {
id
name
...UserFragment
}
}
こんな感じにUserFragmentという共通化を行います。
ただ、このように共通化をおこなっていくと、問題が発生してきます。
みなさんも知っているように、共通化というのは保守性を上げる時もあれば、下げる時もあります。
下手に共通化をおこなっていくと、「オーバーフェッチ」を招いてしまうんです。
Fragmentによるオーバーフェッチとは
Fragmentを使うことでクエリの一部を共通化することができます。
ここで発生してしまうのはFragmentの乱用です。
ユーザーの情報を全て取得してくるUserDetailFragmentをユーザー一覧のページでも利用してしまう。
こういうことが発生してしまいます。
今回はオーバーフェッチについて取り上げましたが、TypeScriptを用いていない場合、型エラーが発生せず、アンダーフェッチ(必要な値が足りない)みたいなことも発生しうるかと思います。
そこで生まれたのがFragment Colocationという概念です。
Fragment Colocationとは?
Colocationというのは一緒の場所において管理する。
みたいな意味合いを持っています。
何と一緒において管理するのかというと、コンポーネントです。
データを欲するコンポーネントに、そのコンポーネントが欲しいだけのデータを一緒にFragmentとして書きましょう。
と言う話です。
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserDetail(props: Props) {
const data = useFragment(
graphql`
fragment UserComponent_user on User {
name
profile_picture(scale: 2) {
uri
}
}
`,
props.user,
);
return (
<>
<h1>{data.name}</h1>
<div>
<img src={data.profile_picture?.uri} />
</div>
</>
);
}
module.exports = UserComponent;
このように、コンポーネントと一対一でFragmentを定義することで、下手に共通化されることを防ごうという概念です。
Fragment Colocationと呼ばれることが多いですが、GraphQLの公式ガイドにもRelayの公式ガイドにもColocationという言葉は載っていない気がします。
正確な呼び名はあまりないのかもしれません。
まとめ
最後までご覧いただきありがとうございました。
今回はGraphQLを導入する上で必要になってくるFragmentという知識について書かせていただきました。