🐥

【暫定対応】router.queryとuseSWRを組み合わせて使う

2022/07/06に公開

課題

  • hooksはuseEffectの中で使えない。
    • ESLint: React Hook "useTrainingBundlePrograms" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.(react-hooks/rules-of-hooks)
  • hooksは条件分岐できない
    • ESLint: React Hook "useSWR" is called conditionally. React Hooks must be called in the exact same order in every component render.(react-hooks/rules-of-hooks)
  • useRouterを使って取得するqueryは初期値がUndefinedになる

上記の理由から、queryに値がセットされてからのみuseSWRが発火していごいい感じにre-fetchしてくれるようにするための方法を調査中。

暫定対応

Repositoryパターンを採用しているので、レポジトリの中でPromiseリジェクトを返し無駄にリクエストさせないようにする。

SampleRepository.ts
~
getSomething(
    id: number
  ): Promise<AxiosResponse<Something>> {
    if (!id) {
      return Promise.reject(new RouteParameterRequiredError(["id"]));
    }
    return Repository.get(fetchRoutes.getSomething(id));
  }
 ~
useSomething.ts
import useSWR from "swr";

import { Something } from "@models/Something";
import {
  fetchRoutes,
  SomethingRepository,
} from "@repositories/SomethingRepository";
import swrResponseFormatter from "@utils/function/swrResponseFormatter";
import { SwrResponse } from "types/swrResponse";

const somethingRepository = new SomethingRepository();
type Response = SwrResponse & {
  something: Something | undefined;
};
const useSomething = (id: number): Response => {
  const { data, error } = useSWR(
    fetchRoutes.getSomething(id),
    () => somethingRepository.getSomething(id)
  );
  const res = swrResponseFormatter(data, error);
  return {
    something: data?.data,
    ...res,
  };
};
export default useSomething;
page.tsx
~
const router = useRouter();
  const { id } = router.query;
  const { something, isLoading, isError, message } = useTrainingBundlePrograms(Number(id));
  useEffect(() => {
    // console.log(something, isLoading, isError, message);
  }, [something]);
~

Discussion