※この記事は「【サーバサイド編】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. 使用する主なファイルの立位置
3. 最初の準備
(1)Next.jsでプロジェクトを作成する
今回はTypeScriptを使用します。(ついでにnpmを使う設定も入れています)
npx create-next-app client --typescript --use npm
(2)クライアントサイドでGraphQLを使用するためインストール
cd client
npm install @apollo/client graphql
(3)サーバへの接続設定を書いていきます。
//インポート
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を作成してその中に書いて下さい。
export const 自分でつけるメソッド名 = gql`{クエリ文}`
{
サーバ側で決めたメソッド名 {
欲しいデータ
}
}
実際に全てのTodoを取得するクエリを書いてみると、下記のようになります。取得可能な項目やサーバ側で決めたメソッド名はGraphiQLを参考にして下さい。
/**
* Todoリスト全件取得.
*/
export const TODO_LIST = gql`
{
getAllTodo {
id
title
finish
category {
id
name
}
}
}
`;
■データを取得して使う
取得してコンソールに出力してみます。書き方は下記の通りです。
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;
取得出来た!
後はいつも通り、データを画面に表示出来るよう整えていきます。
5. データの編集
次にデータの編集(Mutation)を書いていきます。今回はTodoリストにTodoを追加出来るようにしていきましょう。
■クエリを書く
データ取得の際と同じように、まずはクエリを書きます。
今回データ取得の際と異なる点は、()があってその中にごちゃごちゃ書いている点です。これはサーバ側作成時に指定した「args(引数)」に入る値になります。
/**
* 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を追加してみましょう。
/**
* 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つのメソッドを見て行きます。
const [下のメソッド名] = useMutation(queryで付けたメソッド名, {
refetchQueries: [{ query: 再度取得の際に叩きたいクエリ }],
awaitRefetchQueries: true,
});
const メソッド名 = (入力データ) => {
サーバ側で決めたメソッド名({
variables: {
送る値
},
});
};
送る値の値が先ほど設定したqueryの「args」に入るという仕組みです。
データの更新、削除も同じように書くことが出来ます!
6. データの1件取得
これはデータの編集と同じように、取得ですが引数を渡す必要があります。引数がないとどのデータを持ってくればいいのか判断できないためです。
やり方はデータ取得の方法で引数を渡せるようにするだけです。
/**
* Todoリスト1件取得.
*/
export const TODO_ITEM = gql`
query ($id: ID) {
getTodo(id: $id) {
title
category {
id
name
}
}
}
`;
/**
* Todo1件取得.
*/
const { loading, error, data } = useQuery(TODO_ITEM, {
variables: { id: todoId },
});
7. 2つのメソッドを叩く
GraphQLの良いところは、クライアントサイドで欲しいデータを選べることです。このようにサーバ側で設定したメソッドを複数一気に叩くことも出来ます。
ここではサーバ側で設定した「getTodo」というメソッドと「getAllCategory」というメソッドを同時に使ってデータを取得する「TODO_AND_CATEGRY」というメソッドを作成しています。
/**
* 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つ定義してあげます。
export type CategoryType = { id: string; name: string };
export type TodoType = {
id: string;
title: string;
finish: boolean;
category: CategoryType;
};
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