首页 > web前端 > js教程 > 自定义 React hook 以将状态与 URL 同步

自定义 React hook 以将状态与 URL 同步

PHPz
发布: 2024-08-10 18:53:32
原创
1037 人浏览过

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 中是否存在指定的搜索参数。如果是,钩子会解析它并将其用作初始状态。否则,它将回退到提供的默认值。

状态更新:

setParamState 函数会更新内部状态和 URL 中的搜索参数。它使用 JSON.stringify 来序列化状态,允许我们在 URL 中存储复杂的对象。

类型支持:

该钩子通过利用 TypeScript 的泛型和 JSON 解析来支持各种类型(字符串、数字、布尔值和对象)。

第三步:使用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 步:测试 Hook

为了确保 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 共享的状态。

您可以进一步扩展此钩子以处理更复杂的数据结构,但对于大多数用例,此实现将满足您的需求。

(请对文章发表评论,以便我可以做得更好并改进我可能犯的任何错误,提前感谢。)

也欢迎在其他平台关注我

  • Linkedin

  • Github

  • Instagram

以上是自定义 React hook 以将状态与 URL 同步的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板