Maison >interface Web >js tutoriel >Hook React personnalisé pour synchroniser l'état avec l'URL

Hook React personnalisé pour synchroniser l'état avec l'URL

PHPz
PHPzoriginal
2024-08-10 18:53:321029parcourir

Custom React hook to sync state with the URL

Lors de la création d'applications React, il est souvent avantageux de refléter l'état dans l'URL. Cela rend non seulement l'état partageable, mais permet également aux utilisateurs de mettre en signet ou d'actualiser des pages sans perdre leur contexte. Dans cet article, nous allons créer un hook React personnalisé appelé useParamState dans TypeScript. Ce hook fonctionnera comme useState, mais il synchronisera également l'état avec les paramètres de recherche dans l'URL. Surtout, il prendra en charge les valeurs d'objets complexes.

Pourquoi utiliser ParamState ?

Le hook useSearchParams de React Router est excellent pour gérer les paramètres de recherche d'URL, mais les synchroniser avec l'état des composants peut être fastidieux. Le hook useParamState résout ce problème par :

  • Fournir une API simple similaire à useState.
  • Synchronisation automatique de l'état avec les paramètres de recherche d'URL.
  • Prise en charge des types complexes, y compris les objets.

Conditions préalables

  • Compréhension de base de React, TypeScript et React Router.
  • Familiarité avec useState et useEffect.

Implémentation de useParamState

Étape 1 : Mise en place du projet

(Cela suppose que vous savez déjà comment mettre en place un projet React, sinon rendez-vous sur Vite)

Assurez-vous que React-Router-Dom est installé :

npm install react-router-dom

Étape 2 : le hook useParamState

Voici comment implémenter le hook 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;


Comment ça marche

Initialisation :

Le hook commence par vérifier si le paramètre de recherche spécifié existe dans l'URL. Si c’est le cas, le hook l’analyse et l’utilise comme état initial. Sinon, il revient à la valeur par défaut fournie.

Mise à jour de l'état :

La fonction setParamState met à jour à la fois l'état interne et le paramètre de recherche dans l'URL. Il utilise JSON.stringify pour sérialiser l'état, nous permettant de stocker des objets complexes dans l'URL.

Prise en charge des types :

Le hook prend en charge différents types (chaîne, nombre, booléen et objet) en tirant parti des génériques de TypeScript et de l'analyse JSON.

Étape 3 : Utilisation de useParamState

Voyons comment utiliser useParamState dans un composant React :

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;

Étape 4 : tester le crochet

Pour vous assurer que le hook useParamState fonctionne comme prévu, vous pouvez écrire des tests unitaires en utilisant @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' });
});

Conclusion

Le hook useParamState simplifie le processus de synchronisation de l'état avec les paramètres de recherche d'URL, rendant vos applications React plus robustes et conviviales. Avec la prise en charge de types complexes tels que les objets, ce hook est un outil puissant pour gérer l'état qui doit persister lors des rechargements de page ou être partagé via des URL.

Vous pouvez étendre davantage ce hook pour gérer des structures de données encore plus complexes, mais pour la plupart des cas d'utilisation, cette implémentation couvrira vos besoins.

( Commentez l'article pour que je puisse l'améliorer et améliorer les erreurs que j'aurais pu commettre, merci d'avance. )

N'hésitez pas à me suivre également sur d'autres plateformes

  • Linkedin

  • Github

  • Instagram

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn