LoginSignup
0
0

React TypeScript React-Router-Dom v6 クエリパラメータの変更と変更検知

Last updated at Posted at 2024-04-01

求められた仕様

クエリパラメータ関連

  • URLのクエリパラメータに合わせて表示を変更する
  • 画面操作でクエリパラメータを変更できる

ブラウザ操作関連

  • ブラウザの戻るボタンを押したら前のクエリパラメータの状態に戻る
  • リロードしても表示は変わらない

使用技術

  • ReactとTypeScript を使用する
  • 標準的なライブラリであるReact Routerの最新バージョンを使用する
    • パッケージはreact-router-domv6を使用する

実装

配置

弊社のGitHubに配置している。

コード

stringnumberの2つの型でクエリパラメータを値として管理する。
複数のファイルで使用できるよう、カスタムフックで実装した。

useQuery.tsx
import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

export function useQuery() {
    const [searchParams, setSearchParams] = useSearchParams();
    const [str, setStr] = useState<string>('');
    const [num, setNum] = useState<number>(0);

    const getParam = useCallback(
        (key: string) => {
            return searchParams.get(key) || '';
        },
        [searchParams],
    );

    const castStrToNum = useCallback((s: string) => {
        switch (s) {
            case 'NaN':
                return Number.NaN;
            default:
                return Number(s);
        }
    }, []);

    useEffect(() => {
        setStr(getParam('str'));
        setNum(castStrToNum(getParam('num')));
    }, [getParam, castStrToNum]);

    const handleChangeParams = useCallback(
        (newStr: string, newNum: number) => {
            setSearchParams({ str: newStr, num: String(newNum) });
        },
        [setSearchParams],
    );

    return { str, num, castStrToNum, handleChangeParams };
}

結論

  • useSearchParams
    • searchParamsuseEffectの依存配列に含むことでクエリパラメータの変更を検知できる
    • setSearchParamsでクエリパラメータを変更する

以上が結論です。

以降は余談になります。

よくない例

最初は以下のように実装していた。

useQuery.tsx
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

export function useQuery() {
    const location = useLocation();
    
    const [str, setStr] = useState<string>('');
    const [num, setNum] = useState<number>(0);

    useEffect(() => {
        const params = new URLSearchParams(location.search);
        const newStr = params.get('str');
        const newNum = params.get('num');
        setStr(newStr === null ? '' : newStr);
        setNum(newNum === null || newNum === '' ? 0 : newNum);
    }, [location]);

    const [searchParams, setSearchParams] = useSearchParams();
    
    const onChangeParams = (newStr: string, newNum: number) => {
        searchParams.set('str', newStr);
        searchParams.set('num', newNum);
        setSearchParams(searchParams);
    };

    return { str, num, onChangeParams };
}

特に以下がよくなかった。

  • 変更検知のためだけにuseLocation()を使用している
  • クエリパラメータ取得のためだけにURLSearchParams()を使用している
  • クエリパラメータ変更のためだけにuseSearchParams()を使用している

疑問

クエリパラメータ関連のオブジェクトの違い

  • 実装するなかで以下の3つを触ったが、それぞれどう異なるのか
    • searchParams = URLSearchParams()searchParams
    • [searchParams, setSearchParams] = useSearchParams()searchParams
    • location = useLocation()location.search

URLSearchParams

  • 以下のように使用する:
    const searchParams = new URLSearchParams();
    const newSearchParams = new URLSearchParams(searchParams);
    newSearchParams.get('str');
    newSearchParams.set('str', '1');
    
  • Reactに依存しないWeb APIの一部
  • URLのクエリ文字列を解析して操作するためのインターフェースを提供する
  • 任意のクエリ文字列を受け取って解析し、URLSearchParamsオブジェクトを作成する
  • そのオブジェクトからクエリパラメータの取得・変更などができる

useSearchParams

  • 以下のように使用する:
    const [searchParams, setSearchParams] = useSearchParams();
    const [searchParams, setSearchParams] = useSearchParams(searchParamsInit);
    setSearchParams({ str: '1', num: '1' });
    
  • React Router v6 で導入されたフック
  • URL のクエリ文字列を解析して操作するためのインターフェースを提供する
  • 任意のクエリ文字列を受け取って解析し、 URLSearchParams オブジェクトと SetURLSearchParams メソッドを作成する
  • そのオブジェクトからクエリパラメータを取得し、そのメソッドからクエリパラメータを変更できる
  • React の状態として扱われているため、クエリパラメータを変更することがコンポーネントの状態変更となり、関連するコンポーネントが再レンダリングされる

useLocation

  • 以下のように使用する:
    const location = useLocation();
    return <div>Query String: {location.search}</div>;
    
  • React Router v5 以前から存在するフック
  • 現在の URL の location オブジェクトを提供する
  • そのオブジェクトからは、URL のパス、クエリ、ハッシュなど、現在の URL について様々な情報を取得できる
  • 取得できるのみで、操作や管理には直接関与しない

結論

  • URLSearchParamsは純粋なJavaScrip の機能で、任意のクエリ文字列を解析・操作するために使用される
  • useSearchParamsはReact Routerの機能で、クエリパラメータの管理をReactコンポーネントに統合し、状態の更新と連動させるために使用する
  • useLocationはReact Routerの機能で、現在のクエリを提供するが、提供する情報が多いため、追加の操作が必要となる

結果として、今回はReactを使用しているので、状態の更新とレンダリングを連動させるためには、 useSearchParamsがクエリ変更検知元のオブジェクトとクエリ変更方法として最適となった。

逆にReactでURLSearchParamsやuseLocationを使う場合って、どんなとき? [調査中]

  • URLSearchParams は useSearchParams を使うほどでもないときに使いそう
    • そんなことってあるか??
    • 取得だけして変更を検知しないならありえる??
  • useLocation は URL 全体を見るときに使いそう
    • そんなことってあるか??
    • 各種 URL 情報を一括して取得したいときに使いそう

課題

プロジェクトによるが、以下の場合については処理を考える必要があるかもしれない。

  • 必要なクエリパラメータが存在しない場合
  • クエリパラメータが空の場合
  • 不要なクエリパラメータが設定されている場合

脚注

0
0
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
0
0