之前在开发React应用的时候,使用react-router总有些奇怪的感觉,觉得React的路由做得没有vue.js完美。最近想到react-router-dom已经有6版本了,于是决定体验一把。
首先创建一个干净的React应用
yarn create react-app react-router-dom-6-demo
查看react-router-dom所有版本
npm view react-router-dom versions
详细的版本列表如下,其中省略了部分目前来说不重要的版本,而6.0版本目前已经进行到beta测试
[
...
'4.0.0',
...
'5.0.0',
'5.0.1',
'5.1.0',
'5.1.1',
'5.1.2',
'5.2.0',
'6.0.0-alpha.0',
'6.0.0-alpha.1',
'6.0.0-alpha.2',
'6.0.0-alpha.3',
'6.0.0-alpha.4',
'6.0.0-alpha.5',
'6.0.0-beta.0'
]
那么废话不多说,直接下载最后一个版本6.0.0-beta.0
cd react-router-dom-6-demo
yarn add react-router-dom@next
然后打开项目文件,稍作整理,只留下最简洁的内容,保留的文件如下:
然后,尝试从react-router-dom中import部分组件的时候,直接爆了个错误
不要慌,直接手动安装history依赖库,即可立即解决问题。
yarn add history
另外,经过一顿尝试,在将react-router-dom版本切换到6.0.0-alpha.5的时候,一切都安静了。
yarn remove react-router-dom react-router
yarn add react-router@6.0.0-alpha.5 react-router-dom@6.0.0-alpha.5
好吧,环境已经准备好,这还只是开始,接下来就开始动手做一些路由相关的测试。
首先准备以下页面:
首先是主页面mian和欢迎页welcome,如果已经登录则进入主页面,否则进去欢迎页(这里以sessionStorage中是否存在token区分是否已登录),欢迎页中点击登录会记录token并跳转至主页面。
接着对App.js进行改造
import React from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import Main from "./pages/main";
import Welcome from "./pages/welcome";
import NotFound from "./pages/not-found";
import Page1 from "./pages/page1";
import Page11 from "./pages/page1-1";
import Page12 from "./pages/page1-2";
import Page13 from "./pages/page1-3";
import Page2 from "./pages/page2";
import Page3 from "./pages/page3";
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Test />} >
<Route path="/home" element={<Main />} ></Route>
<Route path="/page1" element={<Page1 />}>
<Route path="/page1-1" element={<Page11 />}></Route>
<Route path="/page1-2" element={<Page12 />}></Route>
<Route path="/page1-3" element={<Page13 />}></Route>
</Route>
<Route path="/page2" element={<Page2 />}></Route>
<Route path="/page3" element={<Page3 />}></Route>
</Route>
<Route path="/login" element={<Welcome />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
};
export default App;
function Test() {
return sessionStorage.getItem("token") ? <Main /> : <Navigate to="/login" />;
}
另外主页面和欢迎页代码如下:
main.jsx
import React from "react";
import { useNavigate, Outlet } from "react-router-dom";
const Main = (props) => {
const navigate = useNavigate();
const nav = (path) => {
navigate(path);
}
return (
<React.Fragment>
<div>
<p>main page</p>
<button onClick={() => nav("/")}>Home</button>
<button onClick={() => nav("/page1")}>page1</button>
<button onClick={() => nav("/page2")}>page2</button>
<button onClick={() => nav("/page3")}>page3</button>
<button onClick={() => nav("/page1/page1-2")}>page1-2</button>
<button onClick={() => nav("/page1/page1-3")}>page1-3</button>
<Outlet />
</div>
</React.Fragment>
);
};
export default Main;
welcome.jsx
import React from "react";
import { useNavigate } from "react-router-dom";
const Welcome = (props) => {
const navigate = useNavigate();
const login = () => {
sessionStorage.setItem("token", "xx");
navigate("/", { replace: true });
};
return (
<React.Fragment>
<button ghost onClick={login}>login</button>
</React.Fragment>
);
};
export default Welcome;
mian页面中包含三个子组件page1、page2、page3,而page1中又包含了三个子页面。
page1.jsx
import React from "react";
import { Outlet } from "react-router-dom";
const Main = (props) => {
return (
<React.Fragment>
<p>page 1</p>
<Outlet />
</React.Fragment>
);
};
export default Main;
最终页面层次结构如下
最后做个总结,react-router-dom@6相比之前的版本存在以下一些变化(以上demo中涉及到的)
1.BrowserRouter保持不变;
2.Switch替换成了Routes;
3.Route中统一使用element属性,去掉原来的component和render;
4.子路由可以省略上级路由了,比如/page1/page1-1以往需要写完整的Path,而目前可以继承上级页面的路由了,甚至斜线都可以省略;
5.useNavigate取代useHistory,并且api也有相应的变化;
6.新增了Outlet,作用相当于{this.props.children}
。
总而言之,从主观上看,react-router-dom@6新版本的命名更加容易理解,使用更为简洁了,期待正式版本赶紧发布。