1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React入門】データをfetchするときに便利なカスタムフック

Last updated at Posted at 2022-06-23

はじめに

コンポーネントからロジックを分離するためにカスタムフックがよく使われますね。
今回はAPIからデータをfetchするカスタムフックの書き方について備忘録的にまとめます。

fetchしたデータを使ってコンポーネントをrenderしたいとき

fetchしたデータをもとにrenderするとき、SWRがとても便利です。

カスタムフックの実装

SWRを使うと、fetchしたデータをキャッシュしてrenderに使うことができます。
また、ブラウザのタブを切り替えたときには自動でデータの再検証をしてくれたり、あるいはmutateをinvokeすることで任意のタイミングでデータを再検証することができます。

useFetchData.ts
import useSWR, { mutate } from 'swr';
import { useCallback } from 'react';

export const useFetchData = (
  startFetch: boolean,
) => {
  const key = 'some_unique_key';
  const { data, error } = useSWR(startFetch ? key : null, () => 
    axios.get('your_endpoint_here')
  );

  const refetchData = useCallback(() => {
    mutate(key);
  }, [key]);

  return {
    data,
    isLoading: !data && !error,
    isError: !!error,
    refetchData
  };
};

コンポーネントの実装

startFetch === trueになればfetchが開始されます。
データをfetchしている最中はisLoading === trueとなり、これを使ってロード中の表示ができます。
fetchはもちろん非同期的に行われますが、{ data, isLoading, refetchData } ではresolveされた値が返ってくるので、コンポーネント側では非同期を意識する必要はありません。
また、refetchDataをinvokeすればデータを再検証することができます。
これがあればuseEffectを使ったデータの再検証を代替できますね。

component.tsx
import { useFetchData } from './useFetchData';

export const SomeComponent: React.FC<{}> = ({}) => {
  const [startFetch, setStartFetch] = useState(false);
  const { data, isLoading, refetchData } = useFetchData(startFetch);

  const handleStartFetch = useCallback(() => {
    setStartFetch(true);
  }, []);

  return (
    <>
      <Button onClick={handleStartFetch}>フェッチ開始</Button>
      <Button onClick={refetchData}>データ再検証</Button>
      {isLoading && <LoadingComponent />}
      {!isLoading && data && <ComponentToShowData data={data}/>}
    </>
  );
};

任意のイベントが起きた時にデータをfetchして処理したいとき

たとえば、ボタンを押した時にfetchを開始して何らかの処理をする場合を考えます。
上記のSWRを使ったユースケースと異なるのは、「ボタンを押した時だけ」APIをcallする、という点です。
SWRはとても便利ですが、fetchしたデータはキャッシュされ、さらにブラウザのタブを切り替えた時などに自動でデータ再検証(APIの再call)が行われます。
上記が不要なケースでは下記のようにカスタムフックを書くことができます。
(*SWRでも自動再検証のキャンセルができるようです)

カスタムフックの実装

useFetchData.ts
import { useCallback, useState } from 'react';

interface IData {
  something: string;
}

export const useFetchData = () => {
  const [dataState, setDataState] = useState<{
    data: IData | null;
    isLoading: boolean;
  }>({
    data: null,
    isLoading: false
  });

  const fetchData = useCallback(async () => {
    setDataState({
      data: null,
      isLoading: true
    });
    const data = await axios.get('your_endpoint_here')
    setDataState({ data, isLoading: false });
    return data;
  }, []);

  const fetchDataAndDoSomething = useCallback(async () => {
    const data = await fetchData();
    // do something here
  }, []);

  return { ...dataState, fetchDataAndDoSomething };
};

コンポーネントの実装

component.tsx
import { useFetchData } from './useFetchData';

export const SomeComponent: React.FC<{}> = ({}) => {
  const [startFetch, setStartFetch] = useState(false);
  const { data, isLoading, fetchDataAndDoSomething } = useFetchData();

  return (
    <>
      <Button onClick={fetchDataAndDoSomething}>
        'Fetch data and do something'
        {isLoading && <LoadingComponent />}
      </Button>
    </>
  );
};

参考にさせていただいたもの

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?