如何在 react-router-v6 路由上强制存在 searchParams?
How to enforce presence of searchParams on react-router-v6 route?
什么?
我正在构建一个 React+Typescript 应用程序,它调用 https://swapi.dev 来呈现各种资源的页面,例如 people
、films
或 planets
。
为什么?
我需要确保用户无法操纵 URL,这样他们就可以在不指定 pageNumber
参数的情况下转到 /characters
,如下所示:localhost:3000/character?page=1
怎么办?
例如,我有一条如下所示的路线,如果他们输入 /characters
,我需要将用户重定向到 /characters?page=1
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route
path="characters"
element={<SwapiResourcePage resourceType={"people"}
/>
<Route
path="characters/:id"
element={<SwapiResourceDetailsPage resourceType={"people"}
/>
</Route>
</Routes>
你试过什么?
我已经尝试将路径替换为 path=characters?page=:id
并将其设置为精确,但这在 react-router
中是无效的语法。还快速浏览了 https://reactrouter.com/docs/en/v6/ ,但我找不到任何相关内容。
我能提供什么帮助?
我需要帮助弄清楚如何在 react-router 路由上强制执行 searchParams。
您不能在路由级别执行此操作,因为 queryString 参数不是路径的一部分。只有路径被 react-router-dom
Route
个组件使用。
使用 matched/routed 组件中的 useSearchParams
挂钩并检查 page
queryString 参数,如果缺少则发出命令式后退导航。
示例:
import { useNavigate, useSearchParams } from 'react-router-dom';
const SwapiResourcePage = ({ resourceType }) => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const page = searchParams.get("page");
useEffect(() => {
if (!page) navigate(-1); // <-- no page param, navigate back
}, [navigate, page]);
...
if (!page) {
return null;
}
// render content
...
更新
您的问题似乎更多是关于提供后备 page
queryString 值,而不是在缺少 page
值时阻止访问路由内容。您可以使用与上面相同的 code/logic,但不是使用 navigate
发出路线后退导航,只需更新 queryString。
import { useSearchParams } from 'react-router-dom';
const SwapiResourcePage = ({ resourceType }) => {
const [searchParams, setSearchparams] = useSearchParams();
const page = searchParams.get("page");
useEffect(() => {
if (!page) {
// No page param, replace current
searchParams.set("page", 1);
setSearchparams(searchParams, { replace });
}
}, [searchParams, setSearchparams, page]);
...
if (!page) {
return null;
}
// render content
...
所以,我最终通过创建一个名为 <ValidateQueryParams/>
的中间组件解决了这个问题,这是我为感兴趣的人使用的代码:
import React, { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import validatePageNumber from "../helpers/validatePageNumber";
import SwapiResourcePage from "../pages/SwapiResourcePage";
interface ValidateQueryParamProps {
resourceType: string;
}
const ValidateQueryParam: React.FC<ValidateQueryParamProps> = ({
resourceType,
}) => {
const [searchParams, setSearchParams] = useSearchParams();
const pageNumber = searchParams.get("page");
useEffect(() => {
if (
pageNumber == null ||
!pageNumber.match(/\d+/) ||
!validatePageNumber(resourceType, parseInt(pageNumber))
) {
setSearchParams({ page: "1" });
}
}, []);
return <SwapiResourcePage resourceType={resourceType} />;
};
export default ValidateQueryParam;
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route
path="people"
element={<ValidateQueryParam resourceType={"people"} />}
/>
<Route
path="people/:id"
element={<SwapiResourceDetailsPage resourceType={"people"} />}
/>
</Route>
</Routes>
什么?
我正在构建一个 React+Typescript 应用程序,它调用 https://swapi.dev 来呈现各种资源的页面,例如 people
、films
或 planets
。
为什么?
我需要确保用户无法操纵 URL,这样他们就可以在不指定 pageNumber
参数的情况下转到 /characters
,如下所示:localhost:3000/character?page=1
怎么办?
例如,我有一条如下所示的路线,如果他们输入 /characters
/characters?page=1
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route
path="characters"
element={<SwapiResourcePage resourceType={"people"}
/>
<Route
path="characters/:id"
element={<SwapiResourceDetailsPage resourceType={"people"}
/>
</Route>
</Routes>
你试过什么?
我已经尝试将路径替换为 path=characters?page=:id
并将其设置为精确,但这在 react-router
中是无效的语法。还快速浏览了 https://reactrouter.com/docs/en/v6/ ,但我找不到任何相关内容。
我能提供什么帮助?
我需要帮助弄清楚如何在 react-router 路由上强制执行 searchParams。
您不能在路由级别执行此操作,因为 queryString 参数不是路径的一部分。只有路径被 react-router-dom
Route
个组件使用。
使用 matched/routed 组件中的 useSearchParams
挂钩并检查 page
queryString 参数,如果缺少则发出命令式后退导航。
示例:
import { useNavigate, useSearchParams } from 'react-router-dom';
const SwapiResourcePage = ({ resourceType }) => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const page = searchParams.get("page");
useEffect(() => {
if (!page) navigate(-1); // <-- no page param, navigate back
}, [navigate, page]);
...
if (!page) {
return null;
}
// render content
...
更新
您的问题似乎更多是关于提供后备 page
queryString 值,而不是在缺少 page
值时阻止访问路由内容。您可以使用与上面相同的 code/logic,但不是使用 navigate
发出路线后退导航,只需更新 queryString。
import { useSearchParams } from 'react-router-dom';
const SwapiResourcePage = ({ resourceType }) => {
const [searchParams, setSearchparams] = useSearchParams();
const page = searchParams.get("page");
useEffect(() => {
if (!page) {
// No page param, replace current
searchParams.set("page", 1);
setSearchparams(searchParams, { replace });
}
}, [searchParams, setSearchparams, page]);
...
if (!page) {
return null;
}
// render content
...
所以,我最终通过创建一个名为 <ValidateQueryParams/>
的中间组件解决了这个问题,这是我为感兴趣的人使用的代码:
import React, { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import validatePageNumber from "../helpers/validatePageNumber";
import SwapiResourcePage from "../pages/SwapiResourcePage";
interface ValidateQueryParamProps {
resourceType: string;
}
const ValidateQueryParam: React.FC<ValidateQueryParamProps> = ({
resourceType,
}) => {
const [searchParams, setSearchParams] = useSearchParams();
const pageNumber = searchParams.get("page");
useEffect(() => {
if (
pageNumber == null ||
!pageNumber.match(/\d+/) ||
!validatePageNumber(resourceType, parseInt(pageNumber))
) {
setSearchParams({ page: "1" });
}
}, []);
return <SwapiResourcePage resourceType={resourceType} />;
};
export default ValidateQueryParam;
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route
path="people"
element={<ValidateQueryParam resourceType={"people"} />}
/>
<Route
path="people/:id"
element={<SwapiResourceDetailsPage resourceType={"people"} />}
/>
</Route>
</Routes>