状態を URL と同期するためのカスタム React フック

PHPz
リリース: 2024-08-10 18:53:32
オリジナル
997 人が閲覧しました

Custom React hook to sync state with the URL

React アプリケーションを構築する場合、URL に状態を反映すると有益なことがよくあります。これにより、状態が共有可能になるだけでなく、ユーザーがコンテキストを失うことなくページをブックマークしたり更新したりできるようになります。この投稿では、TypeScript で useParamState というカスタム React フックを作成します。このフックは useState と同様に機能しますが、状態と URL 内の検索パラメーターも同期します。重要なのは、複雑なオブジェクト値をサポートすることです。

なぜParamStateを使用するのでしょうか?

React Router の useSearchParams フックは、URL 検索パラメータの管理に優れていますが、コンポーネントの状態と同期するのは面倒な場合があります。 useParamState フックは、次のようにしてこれに対処します。

  • useState に似た単純な API を提供します。
  • 状態を URL 検索パラメータと自動的に同期します。
  • オブジェクトを含む複合型のサポート。

前提条件

  • React、TypeScript、および React Router の基本的な理解。
  • useState と useEffect についての知識。

useParamStateの実装

ステップ 1: プロジェクトのセットアップ

(これは、React プロジェクトのセットアップ方法をすでに知っていることを前提としています。そうでない場合は、Vite に進んでください)

react-router-dom がインストールされていることを確認してください:

npm install react-router-dom
ログイン後にコピー

ステップ 2: useParamState フック

useParamState フックを実装する方法は次のとおりです。

import { useCallback, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

/**
 * A custom hook that syncs state with a URL search parameter.
 * Supports string, number, boolean, and object values.
 * @param key The search parameter key to sync with.
 * @param defaultValue The default value for the state.
 * @returns A stateful value, and a function to update it.
 */
function useParamState<T extends string | number | boolean | object>(
  key: string,
  defaultValue: T
): [T, (newValue: Partial<T> | T) => void] {
  const [searchParams, setSearchParams] = useSearchParams();
  const paramValue = searchParams.get(key);

  const [state, setState] = useState<T>(() => {
    if (paramValue === null) {
      return defaultValue;
    }
    try {
      return JSON.parse(paramValue) as T;
    } catch {
      return paramValue as T;
    }
  });

  const setParamState = useCallback(
    (newValue: Partial<T> | T) => {
      const updatedValue = typeof newValue === 'object' && !Array.isArray(newValue)
        ? { ...state, ...newValue }
        : newValue;

      setState(updatedValue as T);
      const newSearchParams = new URLSearchParams(searchParams);
      newSearchParams.set(key, JSON.stringify(updatedValue));
      setSearchParams(newSearchParams);
    },
    [key, searchParams, setSearchParams, state]
  );

  return [state, setParamState];
}

export default useParamState;


ログイン後にコピー

仕組み

初期化:

フックは、指定された検索パラメータが URL に存在するかどうかを確認することから始まります。存在する場合、フックはそれを解析し、それを初期状態として使用します。それ以外の場合は、指定されたdefaultValueに戻ります。

状態の更新:

setParamState 関数は、内部状態と URL 内の検索パラメータの両方を更新します。 JSON.stringify を使用して状態をシリアル化し、複雑なオブジェクトを URL に保存できるようにします。

タイプのサポート:

フックは、TypeScript のジェネリックスと JSON 解析を活用することで、さまざまな型 (文字列、数値、ブール値、オブジェクト) をサポートします。

ステップ 3: useParamState の使用

React コンポーネントで useParamState を使用する方法を見てみましょう:

import React from 'react';
import useParamState from './useParamState';

interface FilterState {
  status: string;
  sortBy: string;
}

const MyComponent: React.FC = () => {
  const [filter, setFilter] = useParamState<FilterState>('filter', {
    status: 'all',
    sortBy: 'date',
  });

  return (
    <div>
      <h2>Current Filter: {filter.status}, Sort by: {filter.sortBy}</h2>
      <button onClick={() => setFilter({ status: 'active', sortBy: filter.sortBy })}>
        Active
      </button>
      <button onClick={() => setFilter({ status: 'completed', sortBy: filter.sortBy })}>
        Completed
      </button>
      <button onClick={() => setFilter({ ...filter, sortBy: 'priority' })}>
        Sort by Priority
      </button>
    </div>
  );
};

export default MyComponent;

ログイン後にコピー

ステップ 4: フックをテストする

useParamState フックが期待どおりに動作することを確認するには、@testing-library/react を使用して単体テストを作成します。

import { renderHook, act } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import useParamState from './useParamState';

interface FilterState {
  status: string;
  sortBy: string;
}

test('should sync object state with search params', () => {
  const wrapper = ({ children }: { children: React.ReactNode }) => (
    <MemoryRouter initialEntries={['/']}>{children}</MemoryRouter>
  );

  const { result } = renderHook(() => useParamState<FilterState>('filter', { status: 'all', sortBy: 'date' }), { wrapper });

  // Initial state
  expect(result.current[0]).toEqual({ status: 'all', sortBy: 'date' });

  // Update state and URL
  act(() => {
    result.current[1]({ status: 'active', sortBy: 'priority' });
  });

  // Updated state
  expect(result.current[0]).toEqual({ status: 'active', sortBy: 'priority' });
});

ログイン後にコピー

結論

useParamState フックは、状態を URL 検索パラメータと同期するプロセスを簡素化し、React アプリケーションをより堅牢で使いやすくします。オブジェクトなどの複雑なタイプをサポートするこのフックは、ページのリロード後も保持するか、URL 経由で共有する必要がある状態を管理するための強力なツールです。

このフックをさらに拡張して、さらに複雑なデータ構造を処理することもできますが、ほとんどのユースケースでは、この実装でニーズをカバーできます。

(記事を改善し、間違いを改善できるよう、記事にコメントしてください。よろしくお願いします。)

他のプラットフォームでもお気軽にフォローしてください

  • リンクトイン

  • Github

  • インスタグラム

以上が状態を URL と同期するためのカスタム React フックの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート