Next.js向けのクエリ文字列同期化された状態フック「useQueryState」の使い方


この記事では、「useQueryState」というカスタムフックを使用して、Next.jsアプリケーションでクエリ文字列と状態を同期化する方法を紹介します。このフックは、クエリ文字列の変更に対して状態を自動的に更新し、状態の変更に対してクエリ文字列を更新する機能を提供します。

まず、次のように「useQueryState」フックを実装します。

import { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
function useQueryState(key, defaultValue) {
  const router = useRouter();
  const [value, setValue] = useState(defaultValue);
  useEffect(() => {
    const queryValue = router.query[key];
    if (queryValue !== undefined) {
      setValue(queryValue);
    }
  }, [router.query[key]]);
  useEffect(() => {
    const query = { ...router.query };
    if (value === defaultValue) {
      delete query[key];
    } else {
      query[key] = value;
    }
    router.push({ pathname: router.pathname, query });
  }, [value]);
  return [value, setValue];
}

このカスタムフックは、指定されたキー(クエリ文字列の名前)とデフォルト値を受け取ります。フック内で、ReactのuseStateフックとuseEffectフックを使用して状態を管理し、useRouterフックを使用して現在のクエリ文字列を取得します。

次に、状態の変更とクエリ文字列の変更を監視するために、2つのuseEffectフックを使用します。1つ目のuseEffectフックでは、クエリ文字列が変更された場合に状態を更新します。2つ目のuseEffectフックでは、状態が変更された場合にクエリ文字列を更新し、ページのURLを変更します。

このカスタムフックを使用するには、次のようにコンポーネント内で呼び出します。

import { useRouter } from 'next/router';
import useQueryState from 'path/to/useQueryState';
function MyComponent() {
  const router = useRouter();
  const [search, setSearch] = useQueryState('search', '');
  const handleSearchChange = (e) => {
    setSearch(e.target.value);
  };
  return (
    <div>
      <input type="text" value={search} onChange={handleSearchChange} />
      <button onClick={() => router.push({ pathname: router.pathname, query: { search } })}>
        Search
      </button>
    </div>
  );
}

上記の例では、useQueryStateフックを使用して、searchというクエリ文字列を状態として管理しています。searchの値が変更されると、自動的にクエリ文字列が更新され、URLが変更されます。

このようにして、「useQueryState」フックを使用することで、Next.jsアプリケーションでクエリ文字列と状態を簡単に同期化することができます。これにより、URLパラメータの変更に応じてコンポーネントの表示や振る舞いを制御することができます。また、クエリ文字列と状態の同期化は、ブラウザの履歴管理やブックマーク機能との統合にも役立ちます。

さらに、このカスタムフックを応用して、他のクエリ文字列と状態を同期化する方法もあります。例えば、ページネーションやフィルタリングのためのクエリパラメータを状態として管理することができます。

以下に、他のクエリ文字列と状態を同期化する例を示します。

import { useRouter } from 'next/router';
import useQueryState from 'path/to/useQueryState';
function MyComponent() {
  const router = useRouter();
  const [page, setPage] = useQueryState('page', 1);
  const [category, setCategory] = useQueryState('category', 'all');
  const [sortBy, setSortBy] = useQueryState('sortBy', 'date');
  const handlePageChange = (newPage) => {
    setPage(newPage);
  };
  const handleCategoryChange = (newCategory) => {
    setCategory(newCategory);
  };
  const handleSortByChange = (newSortBy) => {
    setSortBy(newSortBy);
  };
  return (
    <div>
      <div>Page: {page}</div>
      <button onClick={() => handlePageChange(page + 1)}>Next Page</button>
      <div>Category: {category}</div>
      <select value={category} onChange={(e) => handleCategoryChange(e.target.value)}>
        <option value="all">All</option>
        <option value="category1">Category 1</option>
        <option value="category2">Category 2</option>
      </select>
      <div>Sort By: {sortBy}</div>
      <select value={sortBy} onChange={(e) => handleSortByChange(e.target.value)}>
        <option value="date">Date</option>
        <option value="name">Name</option>
      </select>
      <button onClick={() => router.push({ pathname: router.pathname, query: { page, category, sortBy } })}>
        Apply Filters
      </button>
    </div>
  );
}

この例では、pagecategorysortByという3つのクエリパラメータを状態として管理しています。それぞれの状態が変更されると、クエリ文字列が自動的に更新されます。また、それぞれの状態の変更に応じて、表示やフィルタリングのロジックを適用することができます。

以上が、「useQueryState」フックを使用してNext.jsアプリケーションでクエリ文字列と状態を同期化する方法の紹介です。このフックを使うことで、クエリ文字列と状態の管理を簡単に行うことができます。