- 升级react-router-dom包,可以去掉react-router,@types/react-router, @types/react-router-dom的依赖
yarn add react-router-dom
yarn remove react-router @types/react-router @types/react-router-dom
- 用
<Routes>包裹<Route>而不是<Switch>
<Switch>
<Route path="about-us">
...
</Route>
</Switch>
<Routes>
<Route path="about-us">
...
</Route>
</Routes>
- 包裹的组件将不能以children或者component的形式传入,换成element传入,
- exact属性将不再需要,react-router-dom会通过更智能的算法匹配最适合的路由
- component属性将以组件形式传入而不是表达式
<Route exact path="/about" component={About} />
<Route exact path="/about">
<About />
</Route>
<Route path="/about" element={<About />} />
<Route>的嵌套规则和路由匹配规则发生改变,子<Route>中的path将变成相对路径
// v6 只支持:参数匹配和 * 通配符
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
//正则匹配不再支持
/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg
/files-*
- 单独出现时必须被包裹
- 新增用来确定子路由的插入位置
import {
BrowserRouter,
Routes,
Route,
Link,
Outlet,
} from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<Users />
</Route>
</Switch>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Switch>
<Route path="/users/me">
<OwnUserProfile />
</Route>
<Route path="/users/:id">
<UserProfile />
</Route>
</Switch>
</div>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />}>
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Outlet />
</div>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />} />
</Routes>
</BrowserRouter>
);
}
function Users() {
return (
<div>
<nav>
<Link to="me">My Profile</Link>
</nav>
<Routes>
<Route path="me" element={<OwnUserProfile />} />
<Route path=":id" element={<UserProfile />} />
</Routes>
</div>
);
}
<Redirect>替换成<Navigate>
<Switch>
<Redirect from="about" to="about-us" />
</Switch>
<Routes>
<Route path="about" element={<Navigate to="about-us" replace/>} />
</Routes>
<Redirect to="about" />
<Redirect to="home" push />
<Navigate to="about" replace />
<Navigate to="home" />
<Link>传入state的方式改变
import { Link } from "react-router-dom";
<Link to={{ pathname: "/home", state: state }} />
<Link to="/home" state={state} />
- useHistory的hook被去除掉了,替换成了useNavigate
import { useHistory } from "react-router-dom";
function App() {
const { go, goBack, goForward } = useHistory();
return (
<>
<button onClick={() => go(-2)}>
Go 2 pages back
</button>
<button onClick={goBack}>Go back</button>
<button onClick={goForward}>Go forward</button>
<button onClick={() => go(2)}>
Go 2 pages forward
</button>
</>
);
}
import { useNavigate } from "react-router-dom";
function App() {
const navigate = useNavigate();
return (
<>
<button onClick={() => navigate(-2)}>
Go 2 pages back
</button>
<button onClick={() => navigate(-1)}>Go back</button>
<button onClick={() => navigate(1)}>
Go forward
</button>
<button onClick={() => navigate(2)}>
Go 2 pages forward
</button>
</>
);
}
- 因为useHistory和Prompt被去掉,官方没有给出history.block的替代方法,如下用usePrompt和useBlock的hook用来替代history.block, 且usePrompt中抽象了离开页面弹框的逻辑,使用起来更简单
import { useContext, useEffect, useCallback } from "react";
import { UNSAFE_NavigationContext as NavigationContext } from "react-router-dom";
import { Button } from "antd";
import { useNavigate } from "react-router-dom";
export function useBlocker(blocker, when = true) {
const { navigator } = useContext(NavigationContext);
useEffect(() => {
if (!when) return;
const unblock = navigator.block((tx) => {
const autoUnblockingTx = {
...tx,
retry() {
unblock();
tx.retry();
},
};
blocker(autoUnblockingTx);
});
return unblock;
}, [navigator, blocker, when]);
}
export function usePrompt(
when = true,
callback?: (
location: Transition["location"],
action: Transition["action"]
) => boolean,
message?: string
) {
const blocker = useCallback(
(tx: Transition) => {
const result = isUndefined(callback)
? true
: callback(tx.location, tx.action);
if (result) {
useWarnConfirm({ title: message, unsaved: !message }, () => {
tx.retry();
})();
} else {
tx.retry();
}
},
[message]
);
return useBlocker(blocker, when);
}
export default () => {
const navigate = useNavigate();
const when = true;
usePrompt(when, (location, action) => {
console.log(location, action);
return true;
},"确定要离开页面吗",);
const handleLeave = () => {
navigate("/");
};
return <Button onClick={handleLeave}>点击离开页面</Button>;
};
- NavLink中去掉了activeClassName属性,className将接收一个执行函数,通过判断isActive来确定是否命中路由
<NavLink
to="/messages"
- className="nav-link"
- activeClassName="activated"
+ className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
Messages
</NavLink>