React QueryのuseQueryでパラメータ変更に伴う再取得を任意のタイミングで行う

2024/04/13に公開

はじめに

React QueryのuseQueryでパラメータ変更に伴う再取得を任意のタイミングで行う方法をいつも忘れてしまうので備忘録です。

実装例

ホーム画面にて、メモとノートの一覧を表示します。
メモとノートはタブで切り替えることができ、アクティブなタブの場合のみAPIをリクエストします。

home.tsx
export const Home = (): JSX.Element => {
  const [activeTabId, setActiveTabId] = useState(TAB_INDEX_MEMO);
  const [searchWord, setSearchWord] = useState('');

  const {
    data: memos,
    isLoading: isMemoLoading,
    isError: isMemoError,
  } = useGetMemosQuery({
    searchWord,
    options: { enabled: activeTabId === TAB_INDEX_MEMO },
  });
  const {
    data: notes,
    isLoading: isNoteLoading,
    isError: isNoteError,
  } = useGetNotesQuery({
    searchWord,
    options: { enabled: activeTabId === TAB_INDEX_NOTE },
  });

  const tabsWithActiveState = tabs.map((tab) => ({
    ...tab,
    isSelected: tab.id === activeTabId,
  }));

  const handleTabClick = async (tab: DefaultTab): Promise<void> => {
    setActiveTabId(tab.id);
  };

  if (isMemoError) {
    errorToast('メモの取得に失敗しました。');
  }

  if (isNoteError) {
    errorToast('ノートの取得に失敗しました。');
  }

  if (isMemoLoading || isNoteLoading) {
    return <LoadingSpinner />;
  }

  return (
    <>
      <SearchField searchWord={searchWord} setSearchWord={setSearchWord} />

      <div className='grid justify-center bg-neutral-white opacity-95'>
        <SlidableTabs<DefaultTab>
          tabs={tabsWithActiveState}
          onTabClick={handleTabClick}
          getTabKey={(tab) => tab.id}
          getTabName={(tab) => tab.name}
          isSelected={(tab) => tab.isSelected}
        />
      </div>

      <div className='min-h-[600px] overflow-hidden'>
        {activeTabId === TAB_INDEX_MEMO ? (
          <GuestMemoList memos={memos} className='my-8' />
        ) : (
          <GuestNoteList notes={notes} className='my-8' />
        )}
      </div>
    </>
  );
};
getMemos.ts
const getMemos = async (searchWord?: string): Promise<Memo[]> => {
  const url = searchWord
    ? `/v1/memos/search?word=${searchWord}`
    : '/v1/memos/search';
  const data = await fetch.get<Memo[]>(url);

  return data;
};

type UseGetMemosQueryParams = {
  searchWord?: string;
  options?: Omit<
    UseQueryOptions<Memo[], fetch.FetchError>,
    'queryKey' | 'queryFn'
  >;
};

export const useGetMemosQuery = ({
  searchWord,
  options,
}: UseGetMemosQueryParams): UseQueryResult<Memo[], fetch.FetchError> => {
  return useQuery<Memo[], fetch.FetchError>({
    ...options,
    queryKey: [GET_MEMOS_QUERY_KEY, searchWord],
    queryFn: async () => await getMemos(searchWord),
  });
};

オプションenabled

useQueryは、enabledの値がtrueになっているときだけ、リクエストを投げます。
そのため、今回の実装例ではactiveなタブの時だけAPIが投げられます。

queryKeyにパラメーターを含める

queryKeyにsearchWordを含めることで、searchWordの変更でqueryKeyが更新され、自動的にクエリを再実行します。
そのため、useGetMemosQueryにはstateのsearchWordを設定し、SearchFiledで入力 -> 検索ボタン押下でsetSearchWordをすることで、APIが再度リクエストされます。

おわりに

React QueryのuseQueryで任意のタイミングで値を取得する件をまとめてみました。
refetchの方法は良く見るのですが、パラメータ変更に伴う再取得はあまり記事がないように思うので、誰かのためになったら嬉しいです🫶

Discussion