开始之前
路由拦截功能是很常见的,功能。比如:我们的表单没有填写完毕,用户就就要跳转,此时我们需要拦截与确认。在 React-router v6 之前提供了 Prompt
组件用于拦截跳转。React Router v6.19.0
版本之后,开始移除 unstable_
不稳定的前缀变的正式可用
remix 中 useBlocker 从 v2.3.0 开始
Remix 中 useBlocker 钩子函数,从 v2.3.0
开始能够正式使用。
useBlocker 的用法
useBlocker 是一个钩子函数,此钩子函数需要接受一个函数作为参数(或者是 boolean 的值),以下是 useBlocker 相关的 TS 类型:
ts
export declare function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker;
export type BlockerFunction = (args: {
currentLocation: Location;
nextLocation: Location;
historyAction: HistoryAction;
}) => boolean;
export type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;
interface BlockerBlocked {
state: "blocked";
reset(): void;
proceed(): void;
location: Location;
}
interface BlockerUnblocked {
state: "unblocked";
reset: undefined;
proceed: undefined;
location: undefined;
}
interface BlockerProceeding {
state: "proceeding";
reset: undefined;
proceed: undefined;
location: Location;
}
以上是 useBlocker 相关的类型,这些类型
特点
- useBlocker 拦截的是通过 react-router 导航
- 如果手动点击浏览器的导航按钮,useBlocker 是不能拦截的
Remix 中使用示例
tsx
import React from "react";
import { Button, Form, Modal } from "antd";
import { Link, useBlocker } from "@remix-run/react";
export default function ImportantForm() {
const [value, setValue] = React.useState("");
const blocker = useBlocker(
({ currentLocation, nextLocation }) =>
value !== "" && currentLocation.pathname !== nextLocation.pathname
);
return (
<Form method="post">
<label>
请输出数据
<input
name="data"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</label>
<button type="submit">Save</button>
<br />
<Button>
<Link to="/">home</Link>
</Button>
{blocker.state === "blocked" ? (
<div>
<Modal
title="Are you sure you want to leave?"
open={blocker.state === "blocked"}
onOk={() => blocker.proceed()}
onCancel={() => blocker.reset()}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</div>
) : null}
</Form>
);
}
小结
本文主要介绍 React Router 的 useBlocker 的用法,以及基本使用案例。useBlocker 在 v6.19.0 开始正式使用,相比对路由拦截有需求的朋友这个 api 一定非常受用。