Next.jsのSWRでデータを取得するときにaxiosを使った方法をご紹介します。
APIサーバーはLaravelを想定しています。
また、Laravelでデータを返すときはEloquentのAPI Resourcesを使用しているものとします。
https://laravel.com/docs/8.x/eloquent-resources
なので記事データをリクエストした時、APIサーバーが返すデータは以下のとおりです。
{
"data": {
"id": 1,
"title": "タイトル",
...
"created_at": "2021-10-04T08:51:07.000000Z",
"updated_at": "2021-10-04T08:51:08.000000Z"
}
}
Next.jsでの開発がまだイマイチ。。。という方はこちらの書籍がおすすめです。
わかりやすく丁寧にNext.jsの開発が解説されています。
SWRでaxiosを使って取得する
SWRでaxiosを使う場合はuseSWR()
の第2引数にaxiosをしてしたら、SWRはaxiosを使ってデータを取ってきます。
axiosを使ったSWRのコードは以下のとおりです。
記事データの取得を想定しています。
import React, { useEffect } from "react";
import axios from "axios";
import useSWR from "swr";
export type Props = {
query: { id: string };
};
export type fetchPostReturnType = {
data: Post;
};
const PostContainer: React.FC<Props> = (props) => {
const { data, error } = useSWR(
`https://example.com/api/v1/post/${props.query.id}`,
axios
);
return (
...
);
}
取得できたデータは以下の通りです。
{
"data": {
"data": {
"id": 1,
"title": "タイトル",
...
"created_at": "2021-10-04T08:51:07.000000Z",
"updated_at": "2021-10-04T08:51:08.000000Z"
}
},
"status": 200,
"statusText": "OK",
"headers": {
...
},
"config": {
"url": "http://localhost:8000/api/v1/post/10",
...
},
"request": {}
}
このままでは次のように使い勝手が悪いです。
- 不要なデータが多い
- 記事データまでが深い
- 取得したデータが格納される変数名がdataとなり、可読性が悪い
記事のタイトルにアクセスするに以下のようにやりたくないし、
const title = data.data.data.title;
可読性を良くするために記事データをわざわざ以下のように取り出したくない。
const post = data.data.data;
扱いやすいデータを返すようにする
axiosをuseSWR()
の第2引数に入れるだけでデータが取得できて手軽に使えてよかったのですが、以下のように使い勝手の悪いデータが返ってきました。
- 不要なデータが多い
- 記事データまでが深い
- 取得したデータが格納される変数名がdataとなり、可読性が悪い
useSWR()
が返すデータの時点で使い勝手の良いデータになってほしいので、以下のようにコードを改善しました。もちろんtypescript。
import React, { useEffect } from "react";
import axios from "axios";
import useSWR from "swr";
export type Props = {
query: { id: string };
};
export type fetchPostReturnType = {
data: {
id: number;
title: string;
...
};
};
const PostContainer: React.FC<Props> = (props) => {
const fetcher = (url: string): Promise<fetchPostReturnType> =>
axios(url).then((res) => res.data);
const { data: post, error } = useSWR(
`https://example.com/api/v1/post/${props.query.id}`,
fetcher
);
return (
...
);
}
useSWR()
で返すデータを格納する変数名はdataではなくpostに変えています。
そして、そのpostの中のデータは以下の通りです。
{
"data": {
"id": 1,
"title": "タイトル",
...
"created_at": "2021-10-04T08:51:07.000000Z",
"updated_at": "2021-10-04T08:51:08.000000Z"
}
}
大分すっきりして、扱いやすい記事データになりました。
記事タイトルを取得するときは以下のように取得できるようになりました。
const title = post.data.title;
おわりに
コードを改善したことによって以下のようにシンプルで可読性の良いデータを返すようになりました。
- データがシンプルに
- 記事データまでが浅い
- 取得した記事データが格納される変数名がpostとなり、可読性が良い
また、useSWR()
の返り値を格納する変数を変更したことによって、以下のようにuseSWR()
を複数使ってpostデータとcomments
データを取得できるようになりました。
import React, { useEffect } from "react";
import axios from "axios";
import useSWR from "swr";
export type Props = {
query: { id: string };
};
export type fetchPostReturnType = {
data: {
id: number;
title: string;
...
};
};
export type fetchCommentsReturnType = {
data: {
id: number;
comment: string;
...
}[];
};
const PostContainer: React.FC<Props> = (props) => {
// 記事データを取得
const postFetcher = (url: string): Promise<fetchPostReturnType> =>
axios(url).then((res) => res.data);
const { data: post, error: postError } = useSWR(
`https://example.com/api/v1/post/${props.query.id}`,
postFetcher
);
// コメントデータを取得
const commentsFetcher = (url: string): Promise<fetchCommentsReturnType> =>
axios(url).then((res) => res.data);
const { data: comments, error:commentsError } = useSWR(
`https://example.com/api/v1/post/${props.query.id}/comments`,
commentsFetcher
);
return (
...
);
}
typescriptとReactの参考書をまとめておきます。
コメント