我有一个定制的钩子,它将状态存储在URL查询字符串中,构建在Reaction-RouteruseSearchParams钩子的顶部:

import { useSearchParams } from 'react-router-dom';

const decodeSearchParam = (searchParam: string) => {
  try {
    return JSON.parse(searchParam);
  } catch {
    return searchParam;
  }
};

function useSearchParamsState<T = string>(
  searchParamName: string,
  defaultValue: T,
): readonly [
  searchParamsState: T,
  setSearchParamsState: (newState: T) => void,
] {
  const [searchParams, setSearchParams] = useSearchParams();

  const acquiredSearchParam = searchParams.get(searchParamName);
  const searchParamsState = acquiredSearchParam
    ? decodeSearchParam(acquiredSearchParam)
    : defaultValue;

  const setSearchParamsState = (newState: T) => {
    const next = {
      ...Array.from(searchParams.entries()).reduce(
        (o, [key, value]) => ({ ...o, [key]: value }),
        {},
      ),
      [searchParamName]: JSON.stringify(newState),
    };
    setSearchParams(next);
  };
  return [searchParamsState, setSearchParamsState];
}

export default useSearchParamsState;

我面临着一个无法解决的问题,当我同时设置两个参数时,只有最新的参数被考虑在内.

在这场堆叠闪电战中,我有一个问题的复制品:https://stackblitz.com/edit/react-lezj6t?file=src%2FsearchParams.hooks.ts

在这个例子中,如果你点击"set param1",它会将searchParams设置为?param1=1,但如果你点击"set param2 and param3",它只会设置最新的param3,而不是param2,所以searchParams看起来是这样的:?param1=1&param3=3

推荐答案

我可以将两个单独的setSearchParams(searchParams => .....)个呼叫排入队列,以设置单独的搜索参数,并且搜索字符串将按预期使用这两个值进行更新.这是使用104-useSearchParams挂钩.据我所知,使用两个105 useSearchParams钩子导致了一种比以前的searchParams更新的"陈旧闭包".

我在这里的建议是创建一个Reaction上下文提供程序,它可以提供103searchParamssetSearchParamsalluseSearchParamsState的钩子,以便它们都引用相同的闭包.

示例:

SearchParams.hooks.tsx

import { createContext, useContext } from 'react';
import { useSearchParams, SetURLSearchParams } from 'react-router-dom';

const decodeSearchParam = (searchParam: string) => {
  try {
    return JSON.parse(searchParam);
  } catch {
    return searchParam;
  }
};

const SearchParamsStateContext = createContext<[
  searchParams: URLSearchParams,
  setSearchParams: SetURLSearchParams
]>([
  new URLSearchParams(""),
  (search: unknown) => {},
]);

const SearchParamsStateProvider = ({ children }: React.PropsWithChildren<{}>) => {
  const [searchParams, setSearchParams] = useSearchParams();

  return (
    <SearchParamsStateContext.Provider value={[searchParams, setSearchParams]}>
      {children}
    </SearchParamsStateContext.Provider>
  );
};

export function useSearchParamsState<T = string>(
  searchParamName: string,
  defaultValue: T
): readonly [
  searchParamsState: T,
  setSearchParamsState: (newState: T) => void
] {
  const [searchParams, setSearchParams] = useContext(SearchParamsStateContext);

  const acquiredSearchParam = searchParams.get(searchParamName);
  const searchParamsState = acquiredSearchParam
    ? decodeSearchParam(acquiredSearchParam)
    : defaultValue;

  const setSearchParamsState = (newState: T) => {
    setSearchParams(searchParams => {
      searchParams.set(searchParamName, JSON.stringify(newState))
      return searchParams;
    });
  };
  return [searchParamsState, setSearchParamsState];
}

export default SearchParamsStateProvider;
import SearchParamsStateProvider, {
  useSearchParamsState
} from "./searchParams.hooks";

...
<SearchParamsStateProvider>
  <Routes>
    <Route path="/" element={<Layout />}>
      <Route index element={<HomePage />}></Route>
    </Route>
  </Routes>
</SearchParamsStateProvider>

HomePage.tsx

const HomePage = () => {
  const [param1, setParam1] = useSearchParamsState("param1", "");
  const [param2, setParam2] = useSearchParamsState("param2", "");
  const [param3, setParam3] = useSearchParamsState("param3", "");

  const handleClick1 = () => {
    setParam1(1);
  };

  const handleClick2 = () => {
    setParam2(2);
    setParam3(3);
  };

  return (
    <div>
      <div>
        <h1>Home page</h1>
        <p>
          <button onClick={handleClick1}>Set param1</button>
        </p>
        <p>
          <button onClick={handleClick2}>Set param2 and param3</button>
        </p>
        <p>
          <b>list of params:</b> param1: {param1}, param2: {param2}, param3:{" "}
          {param3}
        </p>
      </div>
    </div>
  );
};

Edit react-router-how-to-persist-state-with-usesearchparams

Typescript相关问答推荐

角形标题大小写所有单词除外

将值添加到具有不同类型的对象的元素

具有泛型类型和缺省值的键

类型脚本基于数组作为泛型参数展开类型

如何重构长联合类型?

在包含泛型的类型脚本中引用递归类型A<;-&B

在列表的指令中使用intersectionObservable隐藏按钮

为什么我的导航在使用Typescript的React Native中不起作用?

如何过滤文字中的类对象联合类型?

TYPE FOR ARRAY,其中每个泛型元素是单独的键类型对,然后在该数组上循环

TypeScrip:使用Cypress测试包含插槽的Vue3组件

Typescript不允许在数组中使用联合类型

可以';t使用t正确地索引对象;联合;索引类型

我可以使用对象属性的名称作为对象中的字符串值吗?

Next 13 + React 18 createContext 类型的构建问题

带动态键的 TS 功能

如何将 MUI 主题对象的自定义属性与情感样式组件中的自定义props 一起使用?

TS2532:对象可能未定义

Next.JS-13(应用程序路由)中发现无效的中间件

如何解决 Angular 中的 ts(18048) 错误