公司开了个新的前端react项目,在创建项目的时候试着用了react-router的v6版本,不用不知道,一用吓一跳。我熟悉的Switch呢? Redirect呢?的component/render也不见了?心想我是不是下载错版本了,一看版本号也没啥问题,转头就去啃源码。。。经过一番消化后,心想我去,真香。。。。。。
首先我本次使用的是hooks写法,类写法是否适用目前还没验证,和我使用同样写法的同学可以继续关注下。。。
React Router库中的不同软件包
react-router-dom,react-router-native,
程序包 react-router 是核心库,用作上面列出的他两个程序包的对等依赖项。react-router-dom 是React应用中用于路由的软件包,react-router-native 有用于开发React Native应用的绑定。实际上react-router-dom有react-router的所有web应用相关导出,所以我们所有的东西都可以直接从react-router-dom中直接引用就可以了,这也是官方的推荐做法。
React Router的新特性
<Switch>重命名为<Routes>。<Route>的新特性变更,嵌套路由变得更简单。- 用
useNavigate代替useHistory。 - 新钩子
useRoutes代替react-router-config。 - 大小减少:从
20kb到8kb。 - 使用传参,路由参数使用方法。
<Switch>重命名为<Routes>
从用法上目前没有看出有多大区别,感觉就是换了个名字,这个新的元素是 Switch 组件的升级版,它包括相对路由和链接、自动路由排名、嵌套路由和布局等功能
//v5
<Switch>
<Route path="/" component={Home} />
</Switch>
//v6
<Routes>
<Route path="/" element={<Home />} />
//匹配未定义的路由地址
<Route path={"*"} element={<div>暂无此页面</div>}/>
</Routes>
<Route>的新特性变更,嵌套路由变得更简单。
1.component/render被element替代,而且element只能传入一个React.ReactElement(组件)。
从这个图里我们可以看出,<Route>能用的参数只有4个,index已经被写死了,不可改变,其中element被限制只能上传组件。其余两个目前我这边还没用到(已经够用了其实,以后有时间再去了解下)
2.可以使用套娃模式进行多级路由嵌套的设定
使用<Outlet/>占位
决定子路由的渲染位置,这点是真的舒服,这样我们所有的所有路由都可以在一个App.tsx文件中维护起来,而其他页面只需要 <Outlet/>占个位置就可以方便的处理渲染位置的问题了,简直不要太爽。具体操作请看代码 ⇩⇩
多级路由嵌套的默认路由
如果不注意就会出现页面只渲染了一部分的情况,这种情况在用户手动改变地址栏时会出现。例如地址输入“/”,这时会发现页面只有Home页面内容出来了,而子路由的部分变空了,所以要设置默认路由,当地址输入不全时自动帮用户定位到完整的路由。
在子路由中定义<Route path="" element={<Navigate to={"地址"} />}/>,path也可以设置为‘/父级路由地址’,具体操作请看代码 ⇩⇩
//App.tsx页面
<Routes>
<Route path={`/`} element={<Home />}>
<Route path={`game`} element={<Game />}>
<Route path={"info"} element={<GameInfo />} />
<Route path={"man"} element={<GameMan />} />
//默认路由,path也可以设置为‘/game’,地址为‘/game’时,重定向到"/game/info"
<Route path="" element={<Navigate to={"/game/info"} />} />
</Route>
//默认路由,path也可以设置为‘/’,地址为‘/’时,重定向到"/game/info"
<Route path="" element={<Navigate to={"/game/info"} />} />
</Route>
<Route path={`Index`} element={<Index/>}>
<Route path={"*"} element={<div>暂无此页面</div>}/>
</Routes>
//Home.tsx页面
<HomeHeader>
<div className="headerNav">
<div className="server">
<div>tab1</div>
<div>tab2</div>
<div>tab3</div>
<div>tab4</div>
</div>
</div>
</HomeHeader>
<HomeContent>
//game会在此处(<Outlet/>所在位置)渲染
<Outlet/>
</HomeContent>
注意: <Route path="" element={<Navigate to={"/game/info"} />} />和<Route path={"*"} element={<div>暂无此页面</div>}/> 是不一样的,path=“*”意味着在所有路径都不符合的情况下,而path=“”是父级路由匹配到了,子级路由地址没写时的情况下匹配的子级路由,path=“*”只需要设置一个就好,而path=“”可能要设置很多次。
3. 用useNavigate代替useHistory
这个不知道该如何评价。。。对于用惯了类写法的同学来说,这看着是真难受。。。
现在,
history.push()被替换为navigation(path,{replace:boolean,state:any})
// v5
import { useHistory } from 'react-router-dom';
function Index() {
let history = useHistory();
function handleClick() {
history.push('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
// v6
import { useNavigate } from 'react-router-dom';
function Index() {
let navigate = useNavigate();
function handleClick() {
navigate('/home');
};
return <button onClick={handleClick}>Submit</button>;
};
history的用法也将被替换成:
// v5
history.push('/index');
history.replace('/index');
// v6
navigate('/index');
navigate('/index', {replace: true});
4.新钩子useRoutes代替react-router-config
看起来,简洁了一些,对hooks写法更友好了一些
function App() {
let element = useRoutes([
{ path: '/', element: <Index /> },
{ path: 'dashboard', element: <Dashboard /> },
{ path: 'invoices',
element: <Invoices />,
children: [
{ path: ':id', element: <Invoice /> },
{ path: 'sent', element: <SentInvoices /> }
]
},
// 重定向
{ path: 'index', redirectTo: '/' },
// 404找不到
{ path: '*', element: <NotFound /> }
]);
return element;
}
5. 大小减少:从20kb到8kb。
这个点,没什么好说的了,v6版本相比以前的少了很多方法,和组件,更加精简了。包的体积也是少了一半多。
6. 使用路由传参,路由参数使用方法。
1./index/:id ⇨ useParams
2./index?name="xioaming"&age="18 ⇨ useSearchParams
3.通过路由state传参 ⇨ useLocation