【Next.js】useSWR()でPOSTする

useSWR()を使ってデータを取得するには以下の方法で取得できました。

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
);

useSWR()を使ってデータの取得方法がわからない方は「【Next.js】axiosを使ってSWRで取得する」を参照してください。

同じような方法でPOSTすることはできますが、その方法はオススメできません。

SWR公式ページにも「データ取得のための React Hooks ライブラリ」と書かれています。
SWRはデータ取得専用のReact Hooks ライブラリです。

この記事ではuseSWR()を使ってPOSTする方法とそれがオススメできない理由とオススメのPOSTの方法をご紹介します。

目次

useSWR()を使ってPOST

useSWR()を使って以下のようにポストできますが、この方法はオススメできません。
なぜならこの方法ではSWRの素晴らしい機能が使えないからです。

const fetcher = params => url => post(url, params)
const { data, error } = useSWR(
    `https://example.com/api/v1/post/${props.query.id}/comments`,
    fetcher({comment: val})
);

SWRはデータ取得専用だからPOSTするにはaxiosを使う

冒頭にも紹介しましたが、SWRはデータ取得専用なのでPOSTするにはおとなしくaxiosなどを使いましょう。

こちらの記事がわかりやすいと思います。

https://www.sukerou.com/2019/05/axios.html

データを再取得はuseSWR()のmutate()を使う

useSWR()の返り値にはmutate()があります。

const commentsFetcher = (url: string): Promise<fetchCommentsReturnType> =>
		axios(url).then((res) => res.data);
const { data: comments, error:commentsError, mutate } = useSWR(
		`https://example.com/api/v1/post/${props.query.id}/comments`,
		commentsFetcher
);

mutate()を使ってデータを更新することでSWRの以下の機能が利用できます。

  • stale-while-revalidate(SWR)
  • 再検証
  • ポーリングによるデータの自動再フェッチ
  • 重複排除
  • データのキャッシュ
  • And lot more.

mutate()を使ったデータの更新は以下の順序で行います。

  • axiosやfetchでPOSTする
  • mutate()を使ってデータを更新する

mutate()を使ったデータの更新のサンプルコードは以下の通りです。
POSTはaxiosでもfetchでもいいのですが、今回はaxiosを使用しています。

import React, { useEffect } from "react";
import axios from "axios";
import useSWR from "swr";

export type Props = {
	query: { id: string };
};

...

export type fetchCommentsReturnType = {
	data: {
    id: number;
    comment: string;
    ...
  }[];
};

const PostContainer: React.FC<Props> = (props) => {
  ...

  // コメントデータを取得
  const commentsFetcher = (url: string): Promise<fetchCommentsReturnType> =>
		axios(url).then((res) => res.data);
  const { data: comments, error:commentsError, mutate } = useSWR(
		`https://example.com/api/v1/post/${props.query.id}/comments`,
		commentsFetcher
	);

  const handleOnSubmit = async (e: React.SyntheticEvent): Promise<void> => {
		e.preventDefault();
		const target = e.target as typeof e.target & {
			comment: { value: string };
		};

		const res = await axios.post(
			`https://example.com/api/v1/post/${props.query.id}/comments`,
			{ comment: target.comment.value }
		);

		let newComments = (comments as fetchCommentReturnType).data;
		newComments.push(res.data.data);
		commentsMutate({ ...comments, data: newComments });
	};

  return (
    <form
      ...
      onSubmit={(e) => handleOnSubmit(e)}
    >
      ...
    </form>
  );
}

mutate()を使ったデータの更新方法

mutate()の書式は以下のとおりです。

(alias) mutate(
  key: keyInterface,
  data?: any,
  shouldRevalidate?: boolean | undefined
): Promise<any>

各引数の渡すデータは以下のとおりです。

  • 第1引数(key): URLを指定する
  • 第2引数(data): データ
  • 第3引数: (shouldRevalidate): 再検証の実行

mutate()を使ったデータの更新方法はいくつかあります。

先程のサンプルコードではuseSWR()の返り値のmutate()を使っていたので第1引数のkeyを省略できました。
以下のようにデータを更新しました。

const { data, mutate } = useSWR('/api/user', fetcher)
...
mutate(newUser);

// 再検証なし
// mutate(newUser, false);

しかし、mutate()は上記の書式の通りkeyを指定してデータを更新することもできます。

import React, { useEffect } from "react";
import axios from "axios";
import useSWR, { useSWRConfig } from 'swr'

export type Props = {
	query: { id: string };
};

...

export type fetchCommentsReturnType = {
	data: {
    id: number;
    comment: string;
    ...
  }[];
};

const PostContainer: React.FC<Props> = (props) => {
  const { mutate } = useSWRConfig()
  ...

  // コメントデータを取得
  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
	);

  const handleOnSubmit = async (e: React.SyntheticEvent): Promise<void> => {
		e.preventDefault();
		const target = e.target as typeof e.target & {
			comment: { value: string };
		};

		const res = await axios.post(
			`https://example.com/api/v1/post/${props.query.id}/comments`,
			{ comment: target.comment.value }
		);

		let newComments = (comments as fetchCommentReturnType).data;
		newComments.push(res.data.data);
		mutate(
      `https://example.com/api/v1/post/${props.query.id}/comments`,
      { ...data, name: newName },
      false
    );
	};

  return (
    <form
      ...
      onSubmit={(e) => handleOnSubmit(e)}
    >
      ...
    </form>
  );
}

参照

https://github.com/vercel/swr/issues/93#issuecomment-551110903

typescriptとReactの参考書をまとめておきます。

created by Rinker
¥3,531 (2022/05/15 10:20:51時点 楽天市場調べ-詳細)
created by Rinker
¥2,860 (2022/08/16 19:08:36時点 楽天市場調べ-詳細)
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

エンジニアを目指す方必見!おすすめプログラミングスクール

最短でエンジニアになるには、いかに効率よく学習するかが重要です。モチベーションを維持しながら最短でエンジニアを目指すならプログラミングスクールを利用するのもおすすめです。

コメント

コメントする

目次