qva*_*azi 7 typescript reactjs react-router-dom react-typescript
有路由器
export const router = createBrowserRouter([
{
path: '/todos/:todoId',
element: <Todo />,
loader: todoLoader,
}
]);
Run Code Online (Sandbox Code Playgroud)
有装载机
export const router = createBrowserRouter([
{
path: '/todos/:todoId',
element: <Todo />,
loader: todoLoader,
}
]);
Run Code Online (Sandbox Code Playgroud)
如何根据路径输入参数?
等待路径中指定参数的高亮显示。
更新:感谢@DrewReese @LindaPaiste 提出了以下解决方案。
export const loader: LoaderFunction = async ({ params }) => {
return await fetchData(params.todoId);
};
Run Code Online (Sandbox Code Playgroud)
Dre*_*ese 10
Run Code Online (Sandbox Code Playgroud)declare type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> : Path extends `:${infer Param}` ? Param extends `${infer Optional}?` ? Optional : Param : never; /** * Examples: * "/a/b/*" -> "*" * ":a" -> "a" * "/a/:b" -> "b" * "/a/blahblahblah:b" -> "b" * "/:a/:b" -> "a" | "b" * "/:a/b/:c/*" -> "a" | "c" | "*" */ declare type PathParam<Path extends string> = Path extends "*" ? "*" : Path extends `${infer Rest}/*` ? "*" | _PathParam<Rest> : _PathParam<Path>; export declare type ParamParseKey<Segment extends string> = [ PathParam<Segment> ] extends [never] ? string : PathParam<Segment>; /** * The parameters that were parsed from the URL path. */ export declare type Params<Key extends string = string> = { readonly [key in Key]: string | undefined; };
声明路径的映射/对象(键 - 值),您可以使用 RRDParams和ParamParseKey实用程序类型来提取路线路径参数(方法归功于 LindaPaiste 和 Qvazi)。
declare type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> : Path extends `:${infer Param}` ? Param extends `${infer Optional}?` ? Optional : Param : never;
/**
* Examples:
* "/a/b/*" -> "*"
* ":a" -> "a"
* "/a/:b" -> "b"
* "/a/blahblahblah:b" -> "b"
* "/:a/:b" -> "a" | "b"
* "/:a/b/:c/*" -> "a" | "c" | "*"
*/
declare type PathParam<Path extends string> = Path extends "*" ? "*" : Path extends `${infer Rest}/*` ? "*" | _PathParam<Rest> : _PathParam<Path>;
export declare type ParamParseKey<Segment extends string> = [
PathParam<Segment>
] extends [never] ? string : PathParam<Segment>;
/**
* The parameters that were parsed from the URL path.
*/
export declare type Params<Key extends string = string> = {
readonly [key in Key]: string | undefined;
};
Run Code Online (Sandbox Code Playgroud)
const router = createBrowserRouter([
{
path: Paths.todoDetail,
element: <Todo />,
loader: todoLoader as LoaderFunction
},
]);
Run Code Online (Sandbox Code Playgroud)
但是,该fetchData函数需要一个string类型,因此这里存在不兼容性,因为params.idTodo类型为string | undefined。通过在访问之前进行条件检查来修复此问题
const Paths = {
todoDetail: "/todos/:idTodo",
} as const;
interface TodoLoaderArgs extends ActionFunctionArgs {
params: Params<ParamParseKey<typeof Paths.todoDetail>>;
}
const todoLoader: LoaderFunction = async ({ params }: TodoLoaderArgs) => {
return await fetchData(params.idTodo);
};
Run Code Online (Sandbox Code Playgroud)
或断言它是非空的,例如fetchData(params.idTodo!),或者您可以提供后备,例如fetchData(params.idTodo ?? "")。也许后备可以是数据获取的一些默认查询参数值。
const router = createBrowserRouter([
{
path: Paths.todoDetail,
element: <Todo />,
loader: todoLoader as LoaderFunction
},
]);
Run Code Online (Sandbox Code Playgroud)
这是一个有点迂回的方法,但这似乎是正确键入的并且在运行的codesandbox中工作,但可能有点“hackish”(我的Typescript foo不太好)。要点是您需要重写加载器函数args参数,以便可以重写params属性以包含要在加载器中访问的路径参数。
要覆盖的加载器定义:
Run Code Online (Sandbox Code Playgroud)/** * The parameters that were parsed from the URL path. */ export declare type Params<Key extends string = string> = { readonly [key in Key]: string | undefined; }; /** * @private * Arguments passed to route loader/action functions. Same for now but we keep * this as a private implementation detail in case they diverge in the future. */ interface DataFunctionArgs { request: Request; params: Params; context?: any; } /** * Arguments passed to loader functions */ export interface LoaderFunctionArgs extends DataFunctionArgs { } /** * Route loader function signature */ export interface LoaderFunction { (args: LoaderFunctionArgs): Promise<Response> | Response | Promise<any> | any; }
新的接口声明和用法:
import {
RouterProvider,
createBrowserRouter,
Navigate,
useLoaderData,
LoaderFunction,
LoaderFunctionArgs
} from "react-router-dom";
interface TodoLoaderFunctionArgs extends Omit<LoaderFunctionArgs, "params"> {
params: {
todoId: string;
};
}
interface TodoLoaderFunction extends Omit<LoaderFunction, "args"> {
(args: TodoLoaderFunctionArgs):
| Promise<Response>
| Response
| Promise<any>
| any;
}
const todoLoader: TodoLoaderFunction = async ({ params }) => {
return await fetchData(params.todoId);
};
const router = createBrowserRouter([
{
path: "/todos/:todoId",
element: <Todo />,
loader: todoLoader as LoaderFunction
},
]);
Run Code Online (Sandbox Code Playgroud)
另一种可能更简单的选择是简单地重新铸造params道具。
const todoLoader: LoaderFunction = async ({ params }: TodoLoaderArgs) => {
return params.idTodo ? await fetchData(params.idTodo) : null;
};
Run Code Online (Sandbox Code Playgroud)
小智 5
更简单,这样的事情对我有用:
import type { Params } from "react-router-dom";
export async function loader({ params }: { params: Params<"todoId"> }) {
return await fetchData(params.todoId);
};
Run Code Online (Sandbox Code Playgroud)
如果您有多个参数,则通用参数是一个联合,例如"todoId" | "userId"。
| 归档时间: |
|
| 查看次数: |
5368 次 |
| 最近记录: |