3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Relayのチュートリアルをやってみた

Posted at

はじめに

現在触っているシステムで、Relayを使用しているため、まず理解するために、チュートリアルを行いました。
そこで学んだ内容を、ここにアウトプットいたします。

バージョン18.0.0のDocsを参照しています。

GraphQLの解説は、行いません。

Relayとは

一言でいうと、GraphQLを使ったデータ取得・キャッシュ・同期を最適化し、UIの一貫性を保つためのライブラリです。

そのため、GraphQLとRelayはセットで使用します。

メリット

Relayの最大のメリットは、各コンポーネントが独自のデータ要件をローカルで宣言し、それらの要件をより大きなクエリにまとめることができます。

スクリーンショット 2025-01-04 15.37.51.png

(※ ↑ 公式ドキュメント参照)

各コンポーネントで、Fragmentを用意して、それを大元のクエリで結合させます。
そうすることで、修正が発生した際に、各コンポーネントごとで修正ができます。

デメリット

チュートリアルをやってみましたが、学習コストは高いなと思いました。
直感的に分かる。というより、Relay独自の概念があるので、そこはしっかり抑える必要があるなと思います。

仕組み

スクリーンショット 2025-01-04 15.43.17.png

(※ ↑ 公式ドキュメント参照)

Relay runtimeがコアエンジンとなり、サーバーに向けて、クエリを実行してくれます。
この図から分かるように、各コンポーネントでFragmentを大元のクエリに結合させます。

実装例

import { graphql } from 'relay-runtime';
import { useLazyLoadQuery } from "react-relay";
import type {NewsfeedQuery as NewsfeedQueryType} from './__generated__/NewsfeedQuery.graphql';

export default function Newsfeed({}) {
  const data = useLazyLoadQuery<NewsfeedQueryType>(NewsfeedQuery, {});

  const stories = data.topStories;

  return (
    <div className="newsfeed">
      {stories.map(story =>
        <Story key={story.id} story={story} />)}
    </div>
  );
}

const NewsfeedQuery = graphql`
  query NewsfeedQuery {
    topStories {
      id
      ...StoryFragment
    }
  }
`;

(※ ↑ 公式ドキュメント参照)

NewsfeedQueryで、graphqlでマークされた文字列リテラルを用意します。
これを用意すると、Relayがコンパイルしてくれます。

query NewsfeedQuery { となっているので、これが大元のクエリとなっています。
これを、useLazyLoadQueryでクエリを実行してくれます。

また、...StoryFragmentFragmentになって、各コンポーネントで定義をしていきます。

import { graphql } from 'relay-runtime';
import { useFragment } from 'react-relay';
import type {StoryFragment$key} from './__generated__/StoryFragment.graphql';
import StoryCommentsSection from './StoryCommentsSection';

type Props = {
  story: StoryFragment$key;
};

export default function Story({story}: Props) {
  const data = useFragment(
    StoryFragment,
    story,
  );
  return (
    <Card>
      <Heading>{data.title}</Heading>
      <PosterByline poster={data.poster} />
      <Timestamp time={data.createdAt} />
      <Image image={data.thumbnail} width={400} height={400} />
      <StorySummary summary={data.summary} />
      <StoryCommentsSection story={data} />
    </Card>
  );
}

const StoryFragment = graphql`
  fragment StoryFragment on Story {
    title
    summary
    createdAt
    poster {
      ...PosterBylineFragment
    }
    thumbnail {
      ...ImageFragment @arguments(width: 400)
    }
    ...StoryCommentsSectionFragment
  }
`;

(※ ↑ 公式ドキュメント参照)

上記が、子コンポーネントになります。
fragment StoryFragment on Storyで、Fragmentで定義しています。
それを、useFragmentで実行いたします。

もしFragmentに修正が入れば、コンポーネントごとに修正できるので、わざわざ大元のクエリを変更して...みたいな手間はありません。

図にすると、以下のイメージです。

スクリーンショット 2025-01-04 16.09.58.png

(※ ↑ 公式ドキュメント参照)

コンパイルの方法

Relayは変更すると、必ずコンパイルをし直す必要があります。
これを忘れてしまうと、エラーが出続けてしまいます。

"scripts": {
    "relay": "relay-compiler",
    ...

package.jsonに上記のように記載すると、npm run relayでコンパイルを実行してくれます。

newsfeed % npm run relay

> newsfeed@0.0.0 relay
> relay-compiler

[INFO] [default] compiling...
[INFO] [default] compiled documents: 17 reader, 5 normalization, 18 operation text
[INFO] Done.

まとめ

上記までで、Relayを使用して、データ取得するまでの基本は抑えられたかと思います。
まだこの他にも、学ぶべき箇所はあるかと思います。

  • ページネーション
  • データの再取得 ...etc

メジャーバージョンによっても、実装方法は異なると思うので、扱っているシステムでどのような実装をしているか、確認しようと思います。

ドキュメントは、全て英語になっています。
チュートリアル等は、翻訳をうまく使いながら、挑戦してみてください。

最後までご覧いただき、ありがとうございました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?