Yanonoblog!

こつこつと

フロントエンド(React)における検索機能の実装例

「OpenAPI仕様に基づいて構築されたオープンソースツールセットでありREST APIの設計、作成、文書化に役立つツールです。」

https://outputky.hatenablog.com/entry/2023/03/06/015044

はじめに

本記事ではReactのフックとルーターを使って、URLのクエリパラメータに基づく検索機能の実装例をまとめています。

データの量が多い場合、検索機能があると便利ですよね。

実装内容

クライアントサイドでのフィルタリング

  • すべてのデータを最初にフロントエンドに取得し、その後、ユーザーの入力に基づいてデータをフィルタリングします。

URLベースの検索

  • 検索状態はURLのクエリパラメータとして保存されるため、ページの再読み込み時に検索状態を維持できます。

実装手順

必要なモジュールをインポート

初めに、必要なライブラリや関数をインポートします。

import { useState, useEffect, useCallback } from 'react';
import { getData } from '../../../../apis/sample/path';
import { DataType } from '../../../../interfaces/sampleType';
import { useLocation, useNavigate } from 'react-router-dom';
import { parseQueryParams, getURLParams } from '../../../../utils/strings';
parseQueryParams

サンプル

/**
 * クエリストリングを解析し、オブジェクトに変換
 * @param {Object} defaults デフォルトのパラメーター
 * @param {string} queryString URLのクエリストリング
 * @returns {Object} キーと値のペアを持つオブジェクト
 */
function parseQueryParams(defaults, queryString) {
    const params = new URLSearchParams(queryString);
    const parsed = {};
    for (let [key, value] of params.entries()) {
        parsed[key] = value;
    }
    return { ...defaults, ...parsed };
}

解説

この関数は、URLSearchParams インターフェイスを使用してクエリストリングを解析することでURLからのキーと値のペアを簡単に取得できます。

デフォルトのパラメーターも与えられるので、指定されたクエリパラメータが存在しない場合はデフォルトの値が使用されます。

getURLParams

サンプル

/**
 * オブジェクトをクエリストリングに変換
 * @param {Object} obj キーと値のペアを持つオブジェクト
 * @returns {string} クエリストリング
 */
function getURLParams(obj) {
    const params = new URLSearchParams();
    for (let [key, value] of Object.entries(obj)) {
        params.append(key, value);
    }
    return '?' + params.toString();
}

解説

この関数もURLSearchParams インターフェイスを使用しますが、この場合はオブジェクトをクエリストリングに変換するために使用されます。

オブジェクトの各エントリを繰り返し、それをURLSearchParams インスタンスに追加し、最後に整形されたクエリストリングを返します。

これらの関数を組み合わせることで、Reactアプリケーション内でURLのクエリストリングを操作することができます。

ステートの設定

ReactのuseStateフックを使用して、アプリの状態を管理します。allDataAPIから取得したすべてのデータを保持し、filteredDataはフィルタリングされたデータを保持します。

const [allData, setAllData] = useState<DataType[]>([]);
const [filteredData, setFilteredData] = useState<DataType[]>([]);

クエリパラメータの初期化

useLocationフックで現在のURLの情報にアクセスします。この情報を元に、検索クエリの初期状態を設定します。

こうすることで、URLから直接検索状態を取得できます。

const location = useLocation();
const initialQuery = parseQueryParams({ query: "" }, location.search);
const [searchTerm, setSearchTerm] = useState<string>(initialQuery.query || "");

データ取得と初期フィルタリング

useEffectフックを使用して、ページロード時にデータを取得します。取得したデータはallDataに格納され、その後検索クエリに基づいてフィルタリングされます。

useEffect(() => {
    getData().then(response => {
      setAllData(response.data.items);

      if (searchTerm) {
        const filtered = response.data.items.filter(item =>
          item.name.includes(searchTerm) || item.tag.includes(searchTerm)
        );
        setFilteredData(filtered);
      } else {
        setFilteredData(response.data.items);
      }
    });
}, [searchTerm]);

検索処理

ユーザーが検索ボタンをクリックしたとき、または検索テキストを変更したときにonSearch関数が呼び出されます。

この関数は、入力された検索クエリを元にデータをフィルタリングし、結果をfilteredDataに保存します。

const onSearch = useCallback(() => {
    const filtered = allData.filter(item =>
      item.name.includes(searchTerm) || item.tag.includes(searchTerm)
    );
    setFilteredData(filtered);

    const queryParams = getURLParams({ query: searchTerm });
    navigate(`${location.pathname}${queryParams}`);
}, [allData, searchTerm]);

メリットとデメリット

メリット

ユーザーエクスペリエンスの向上

  • サーバーサイドとの通信が少ないため、レスポンスが高速

状態の共有が容易

  • URLに検索状態が保存されるため、そのURLを共有するだけで状態を他のユーザーと共有できる
デメリット

初回ロードが遅くなる可能性

  • 大量のデータを前もって取得する必要があるため、初回のロード時間が長くなりそう

データの変更に弱い

  • データが頻繁に変更される場合、都度フロントエンドのデータも更新する必要がある

おしまい

コメント

本記事の内容は以上になります!


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky