【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

また、Next.jsとAPIサーバーの通信はこちらの書籍が参考になります。

データを再取得は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

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする


The reCAPTCHA verification period has expired. Please reload the page.

目次