useHref
useHref钩子返回一个URL,该URL可以用来链接到指定的位置,即使是在React路由器之外。
declare function useHref(to: To): string;
Tip:
可以看看react-router-dom中的Link组件,如何用useHref决定自己的href值的
const Link = React.forwardRef(
({
onClick,
replace = false,
state,
target,
to,
...rest
}, ref) => {
let href = useHref(to);
let handleClick = useLinkClickHandler(to, {
replace,
state,
target,
})
return (
<FancyPantsLink
{...rest}
href={href}
onClick={(event) => {
onClick?.(event);
if (!event.defaultPrevented) {
handleClick(event);
}
}}
/>
)
}
)
useInRouterContext
declare function useInRouterContext(): boolean;
如果组件是渲染在Router上下文中,useInRouterContext hook将会返回true,否则返回false。
这个常用于第三方拓展库判断自己是否处于React Router环境中。
useLinkClickHandler
declare function useLinkClickHandler<
E extends Element = HTMLAnchorElement
>(
to: To,
options?: {
target?: React.HTMLAttributeAnchorTarget;
replace?: boolean;
state?: any;
}
): (event: React.MouseEvent<E, MouseEvent>) => void;
useLinkClickHandler hook在建立一个自定义Link的时候,返回了一个点击事件处理器用于导航。
import {
useHref,
useLinkClickHandler,
} from "react-router-dom";
const StyledLink = styled("a", { color: "fuchsia" });
const Link = React.forwardRef(
(
{
onClick,
replace = false,
state,
target,
to,
...rest
},
ref
) => {
let href = useHref(to);
let handleClick = useLinkClickHandler(to, {
replace,
state,
target,
});
return (
<StyledLink
{...rest}
href={href}
onClick={(event) => {
onClick?.(event);
if (!event.defaultPrevented) {
handleClick(event);
}
}}
ref={ref}
target={target}
/>
);
}
);
useLinkPressHndler
declare function useLinkPressHandler(
to: To,
options?: {
replace?: boolean;
state?: any;
}
): (event: GestureResponderEvent) => void;
常用于React-Native,对应着useLinkClickHandler,为自定义Link返回一个按压事件处理器
import { TouchableHighlight } from "react-native";
import { useLinkPressHandler } from "react-router-native";
function Link({
onPress,
replace = false,
state,
to,
...rest
}) {
let handlePress = useLinkPressHandler(to, {
replace,
state,
});
return (
<TouchableHighlight
{...rest}
onPress={(event) => {
onPress?.(event);
if (!event.defaultPrevented) {
handlePress(event);
}
}}
/>
);
}
useLoction
declare function useLocation(): Location;
interface Location extends Path {
state: unknown;
key: Key;
}
hook返回当前location对象,可用于当location改变时,执行一些effect
import * as React from 'react';
import { useLocation } from 'react-router-dom';
function App() {
let location = useLocation();
React.useEffect(() => {
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
useMatch
declare function useMatch<ParamKey extends string = string>(
pattern: PathPattern | string
): PathMatch<ParamKey> | null;
给定相对路径,返回所匹配路由的相关数据
export interface PathMatch<ParamKey extends string = string> {
// URL中的动态参数,如?id=123&&name=kk,id和kk就是两个动态参数
params: Params<ParamKey>;
pathname: string;
// 子路由之前匹配的URL部分
pathnameBase: string;
pattern: PathPattern;
}
useNavigate
declare function useNavigate(): NavigateFunction;
interface NavigateFunction {
(
to: To,
options?: { replace?: boolean; state?: any }
): void;
(delta: number): void;
}
useNavigate hook返回了一个函数,可以让你编程式导航。如果用了replace:true,在history栈中,它将会代替当前的入口,而不是添加一个新的进去。
import { useNavigate } from 'react-router-dom';
function SignupForm() {
let navigate = useNavigate();
async function handleSubmit(event) {
event.preventDefault();
awat sunmitForm(event.target);
navigate('../success'. { replace: true })
}
return <form onSubmit={handleSubmit}>{...}</form>
}
useNavigateType
declare function useNavigationType(): NavigationType;
type NavigationType = "POP" | "PUSH" | "REPLACE";
返回导航的类型,表示user是如何来到当前页面的;是在history stack中通过pop,push还是replace
useOutlet
declare function useOutlet(): React.ReactElement | null;
为子路由返回React元素。内部也是通过来渲染子路由的
useOutletContext
declare function useOutletContext<
Context = unknown
>(): Context;
想和其他子路由共享父路由管理状态或者值,可以创建context provider,它已经内置于Outlet中了
function Parent() {
const [count, setCount] = React.useState(0);
return <Outlet context={[count, setCount]} />
}
import { useOutletContext } from 'react-router-dom'
function Child() {
const [count, setCount] = useOutletContext();
const increment = () => setCount(c => c + 1);
return <button onClick={increment}>{count}</button>
}
如果使用的是TypeScript,官方建议父组件提供一个自定义hook来获取context值。
// dashboard.js
import React from 'react'
import type { User } from "./types";
import { Outlet, useOutletContext } from "react-router-dom";
export default function Dashboard() {
const [user, setUser] = React.useState<User | null>(null);
return (
<div>
<h1>Dashboard</h1>
<Outlet context={{ user }} />
</div>
);
}
// 自定义hook
export function useUser() {
return useOutletContext<ContextType>();
}
import { useUser } from "../dashboard";
export default function DashboardMessages() {
const { user } = useUser();
return (
<div>
<h2>Messages</h2>
<p>Hello, {user.name}!</p>
</div>
);
}
useParams
declare function useParams<
K extends string = string
>(): Readonly<Params<K>>;
useParams hook返回了当前URL动态参数的键值对
import React from 'react';
import { Routes, Route, useParams } from 'react-router-dom';
function ProfildPage() {
let { userId } = useParams();
}
function App() {
return (
<Routes>
<Route path="users">
<Route path=":userId" element={<ProfilePage />} />
<Route path="me" element={...} />
</Route>
</Routes>
);
}
useResolvedPath
declare function useResolvedPath(to: To): Path;
根据给定的to值解析当前location的pathname
这有助于从相对路径中建立links。比如,在NavLink源码内部调用了useResolvedPath解析了页面对应的完整pathname
export const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
function NavLinkWithRef(
{
"aria-current": ariaCurrentProp = "page",
caseSensitive = false,
className: classNameProp = "",
end = false,
style: styleProp,
to,
children,
...rest
},
ref
) {
let location = useLocation();
let path = useResolvedPath(to); // useResolvedPath获得完整的pathname
let locationPathname = location.pathname;
let toPathname = path.pathname;
if (!caseSensitive) {
locationPathname = locationPathname.toLowerCase();
toPathname = toPathname.toLowerCase();
}
let isActive =
locationPathname === toPathname ||
(!end &&
locationPathname.startsWith(toPathname) &&
locationPathname.charAt(toPathname.length) === "/");
let ariaCurrent = isActive ? ariaCurrentProp : undefined;
let className: string | undefined;
if (typeof classNameProp === "function") {
className = classNameProp({ isActive });
} else {
className = [classNameProp, isActive ? "active" : null]
.filter(Boolean)
.join(" ");
}
let style =
typeof styleProp === "function" ? styleProp({ isActive }) : styleProp;
return (
<Link
{...rest}
aria-current={ariaCurrent}
className={className}
ref={ref}
style={style}
to={to}
>
{typeof children === "function" ? children({ isActive }) : children}
</Link>
);
}
);
useRoutes
useRoutes hook等价于Routes,但它使用js定义路由,而不是jsx。这些对象有着和Route元素一样的属性。useRoutes返回值可以是一个合法的React element,用来渲染route tree或者null
import * as React from "react";
import { useRoutes } from "react-router-dom";
fucntion Apoo() {
let element = useRoutes([
path: '/',
element: <Dashboard />,
chlidren: [
{
path: 'message',
element: <DashboardMessage />
},
{
path: 'tasks',
element: <DashboardTasks />
}
]
])
}
useSearchParams
用于读取和修改URL中的query字符串,和useState一样,useSearchParams返回了带有两个值的数组:当前的location的search参数,更新参数的函数
let [searchParams, setSearchParams] = useSearchParams();
import * as React from "react";
import { useSearchParams } from "react-router-dom";
function App() {
let [searchParams, setSearchParams] = useSearchParams();
function handleSubmit(event) {
event.preventDefault();
let params = serializeFormuery(event.target);
setSearchParams(params);
}
return (
<div>
<form onSubmit={handleSubmit}>{/* ... */}</form>
</div>
);
}
setSearchParams函数的工作原理类似于导航,但只用于URL的搜索部分。setSearchParams的第二个参数也是和navigate一样。