1
Help us understand the problem. What are the problem?

posted at

updated at

【クライアントサイド編】GraphQLを使うぞ(TypeScript, Next.js使用)

※この記事は「【サーバサイド編】GraphQLを使うぞ」の続きになります。

こんにちは!今回はGraphQLを使ってTodoアプリを開発していきたいと思います。前回作成したサーバサイドと接続していく形です。(Next.jsの使い方には詳しく触れませんのでご了承ください。)

目次

1.使用技術
2.使用する主なファイルの立位置
3.最初の準備
4.データを全件取得
5.データの編集
6.データの1件取得
7.2つのメソッドを叩く
8.型について
9.まとめ

1. 使用技術

GraphQLではかなり細かく型が設定できるのでJavaScriptを使用しましたが、今回はTypeScriptを使用しました。
・Windows(10)
・言語:TypeScript
・フレームワーク:Next.js
・DB:MongoDB
・GraphQL(Nodeの中で使うイメージ)
Apollo Client

2. 使用する主なファイルの立位置

image.png

3. 最初の準備

(1)Next.jsでプロジェクトを作成する

今回はTypeScriptを使用します。(ついでにnpmを使う設定も入れています)

コマンドプロンプト(ターミナル)
npx create-next-app client --typescript --use npm

(2)クライアントサイドでGraphQLを使用するためインストール

コマンドプロンプト(ターミナル)
cd client
npm install @apollo/client graphql

(3)サーバへの接続設定を書いていきます。

_app.tsx
//インポート
import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql,
} from "@apollo/client";

//GraphQLのURL(エンドポイント)にする
const client = new ApolloClient({
  uri: "http://localhost:4000/graphql",
  cache: new InMemoryCache(),
});

function MyApp({ Component, pageProps }: AppProps) {

//ApolloProviderで囲むとその範囲でGraphQLが使えるようになる
  return (
    <Layout>
      <ApolloProvider client={client}>
        <Component {...pageProps} />
      </ApolloProvider>
    </Layout>
  );
}

export default MyApp;

今はサーバのURLがlocalhostですが、サーバ側をデプロイした後はここをそのURLに変えて、.envファイルとかに書いた方が良いかもです。

4. データを全件取得

■queryを書く

前回のこの部分で書いた、GraphiQLを基にquery文を書いていきます。
queries>query.tsを作成してその中に書いて下さい。

queryの書き方
export const 自分でつけるメソッド名 = gql`{クエリ文}`
queryの中の項目
 {
    サーバ側で決めたメソッド名 {
    欲しいデータ
    }
  }

実際に全てのTodoを取得するクエリを書いてみると、下記のようになります。取得可能な項目やサーバ側で決めたメソッド名はGraphiQLを参考にして下さい。

queries>query.ts
/**
 * Todoリスト全件取得.
 */
export const TODO_LIST = gql`
  {
    getAllTodo {
      id
      title
      finish
      category {
        id
        name
      }
    }
  }
`;

■データを取得して使う

取得してコンソールに出力してみます。書き方は下記の通りです。

index.tsx
import type { NextPage } from "next";
import { useQuery } from "@apollo/client";
import { TODO_LIST } from "../queries/query";

const Home: NextPage = () => {
//useQuery(query.tsで名付けたメソッド名)
  const { loading, error, data } = useQuery(TODO_LIST);

  console.dir(JSON.stringify(data));

  //読み込み中時の表示
  if (loading) {
    return <p>loding…</p>;
  }
  //エラー時の表示
  if (error) {
    return <p>Error</p>;
  }

  return (<></>);
};

export default Home;

取得出来た!
image.png
後はいつも通り、データを画面に表示出来るよう整えていきます。

5. データの編集

次にデータの編集(Mutation)を書いていきます。今回はTodoリストにTodoを追加出来るようにしていきましょう。

■クエリを書く

データ取得の際と同じように、まずはクエリを書きます。
今回データ取得の際と異なる点は、()があってその中にごちゃごちゃ書いている点です。これはサーバ側作成時に指定した「args(引数)」に入る値になります。

queries>query.ts
/**
 * Todoリスト追加.
 */
export const ADD_TODO = gql`
  mutation ($title: String, $categoryId: ID) {
    addTodo(title: $title, categoryId: $categoryId) {
      title
    }
  }
`;

Todoリスト追加する際に必要な情報は「新たなTodoのタイトル」と「カテゴリID」です。そのためその2つが入れられるようになっています。

 mutation ($項目1の入力値: 項目1の型, $項目2の入力値: 項目2の型) {
    サーバ側で決めたメソッド名(項目1: $項目1の入力値, 項目2: $項目2の入力値) {
      追加後に返して欲しいデータ
    }

■データを編集する

それでは上記のqueryを使って、Todoを追加してみましょう。

index.tsx
  /**
   * addTodo後データ再読み込み.
   */
  const [addTodo] = useMutation(ADD_TODO, {
    refetchQueries: [{ query: TODO_LIST }],
    awaitRefetchQueries: true,
  });

  /**
   * Todo追加.
   * @param data - 入力データ
   */
  const addTodoData = (data) => {
    addTodo({
      variables: {
        title: data.todoTitle,
        categoryId: data.categoryId,
      },
    });
  };

下の「Todo追加」が行われた後、上の「addTodo後データ再読み込み.」が動いてリアルタイムに画面上のデータの更新がなされます。Todoを追加した瞬間に画面上に新たなTodoが追加表示されるという訳です。では1つ1つのメソッドを見て行きます。

index.tsx > addTodo後データ再読み込み
  const [下のメソッド名] = useMutation(queryで付けたメソッド名, {
    refetchQueries: [{ query: 再度取得の際に叩きたいクエリ }],
    awaitRefetchQueries: true,
  });
index.tsx > Todo追加
  const メソッド名 = (入力データ) => {
    サーバ側で決めたメソッド名({
      variables: {
       送る値
      },
    });
  };

送る値の値が先ほど設定したqueryの「args」に入るという仕組みです。

データの更新、削除も同じように書くことが出来ます!

6. データの1件取得

これはデータの編集と同じように、取得ですが引数を渡す必要があります。引数がないとどのデータを持ってくればいいのか判断できないためです。

やり方はデータ取得の方法で引数を渡せるようにするだけです。

queries > query.ts
/**
 * Todoリスト1件取得.
 */
export const TODO_ITEM = gql`
  query ($id: ID) {
    getTodo(id: $id) {
      title
      category {
        id
        name
      }
    }
  }
`;

index.tsx
 /**
   * Todo1件取得.
   */
  const { loading, error, data } = useQuery(TODO_ITEM, {
    variables: { id: todoId },
  });

7. 2つのメソッドを叩く

GraphQLの良いところは、クライアントサイドで欲しいデータを選べることです。このようにサーバ側で設定したメソッドを複数一気に叩くことも出来ます。

ここではサーバ側で設定した「getTodo」というメソッドと「getAllCategory」というメソッドを同時に使ってデータを取得する「TODO_AND_CATEGRY」というメソッドを作成しています。

queries > query.ts
/**
 * Todoリスト1件+カテゴリ全データ取得.
 */
export const TODO_AND_CATEGRY = gql`
  query ($id: ID) {
    getTodo(id: $id) {
      title
      category {
        id
        name
      }
    }
    getAllCategory {
      id
      name
    }
  }
`;

■引数が複数にわたる場合の例

ポイントは
・どの引数がどこに入るか区別出来るようにする事
・返ってきたデータを区別するために名前(今回はtodo1等)名前を付けてあげる事

/**
 * Todoリストを同時に3件追加追加.
 */
export const ADD_THREE_TODO = gql`
  mutation (
    $title1: String
    $categoryId1: ID
    $title2: String
    $categoryId2: ID
    $title3: String
    $categoryId3: ID
  ) {
    todo1: addTodo(title: $title1, categoryId: $categoryId1) {
      title
    }
    todo2: addTodo(title: $title2, categoryId: $categoryId2) {
      title
    }
    todo3: addTodo(title: $title3, categoryId: $categoryId3) {
      title
    }
  }
`;

8. 型について

取得したデータの型はAPIでデータ取得の際と同じように、1つ1つ定義してあげます。

types > type.ts
export type CategoryType = { id: string; name: string };

export type TodoType = {
  id: string;
  title: string;
  finish: boolean;
  category: CategoryType;
};
index.tsx
const { loading, error, data } = useQuery(TODO_LIST);

const [dataArray, setDataArray] = useState<Array<TodoType>>([]);
setDataArray(data?.getAllTodo);

余談?ですが、GraphQLの型定義は「GraphQL Code Generator」を使うと楽という事で、別のプロジェクトではこちらも少し使用してみました。コマンドを叩くだけで型が作成されるので楽ですが、若干クエリやJestでの書き方が変わる…?ようなので慣れるまでが少し大変そうでした。覚えてしまえば断然楽かと思います。

9. まとめ

今回はGraphQLを使ってTodoリストを作成しました。
まだまだ未熟な部分が多いので、何か気になる点や誤りがあればご連絡下さい。

ここまでご覧頂き、ありがとうございました。

おまけ:作成したTodoアプリのGitHub

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
1
Help us understand the problem. What are the problem?