利用 typescript 写 react-router 5
不再提倡中心化路由!嵌套路由不再是
{ props.children }
的用法了。每个路由都是一个 React 组件。
react-router-dom
在 web 端使用,只需要导入这个包就可以了,因为它从 react-router
中拿过来了很多东西。
// @types/react-router-dom/index.d.ts export { …… } from 'react-router';
然后看看常用的有哪些功能
HashRouter / BrowerRouter
理解为路由容器,被包裹在里面的子组件就可以使用自己定义的路由组件了。
// index.tsx import React from 'react'; import ReactDOM from 'react-dom'; import { HashRouter } from 'react-router-dom'; import App from './App'; ReactDOM.render( <HashRouter> <App /> </HashRouter> , document.getElementById('root') );
Route
路由组件,路由匹配时这个位置被渲染成相应的内容。
-
path
需要匹配的路径 -
component
匹配成功渲染的组件 -
exact
是否严格匹配
<Route path="/home" exact component={ Home } />
这个例子中,只有当路径为 /home
时才会匹配。若没有 exact
属性,那么当路径为 /home
时,/
、/home
这两个路由组件都会被渲染。
嵌套路由
v4 以上版本不再支持 { props.children }
的方式进行嵌套路由,而是直接把子路由组件放在父组件中需要渲染的位置。
// App.tsx <div> <Route path="/" component={ Dashboard } /> </div> // Dashboard.tsx <div> <Header /> <Route path="/home" component={ Home } /> <Route path="/other" component={ Other } /> </div>
这样的嵌套路由写法,需要保证父组件与子组件有相同的路由前缀(/
),且父组件没有 exact
属性。(目的是先渲染父组件,再匹配父组件内部定义的子路由组件)
动态路由
和其他路由插件一样,使用冒号配置动态路由。
// Dashboard.tsx <div> <Header /> <Route path="/home" component={ Home } /> <Route path="/other" exact component={ Other } /> <Route path="/other/:id" component={ OtherDetail } /> </div>
/other/1
会匹配 /other
和 /other/:id
这两个路由组件,根据实际情况对 /other
路由组件设置 exact
属性。
useParams 获取路由参数
// @types/react-router/index.d.ts export function useParams<Params extends { [K in keyof Params]?: string } = {}>(): { [p in keyof Params]: string };
useParams()
方法返回的是一个对象,直接取属性 TS 会提示空对象中不存在这个属性。按照 TS 的规范,可以在动态路由组件中,定义一个接口约定路由传递的参数。
// OtherDetail.tsx import React from 'react'; import { useParams } from 'react-router-dom'; interface RouteParams { id: string } export default () => { const params = useParams<RouteParams>(); return ( <div> 动态路由:{ params.id } </div> ) }
props 获取路由参数
路由组件的 props
数据类型为 RouteComponentProps
// @types/react-router/index.d.ts export interface RouteComponentProps<Params extends { [K in keyof Params]?: string } = {}, C extends StaticContext = StaticContext, S = H.LocationState> { history: H.History; location: H.Location<S>; match: match<Params>; staticContext?: C; }
其中 match
属性会用的比较多
// @types/react-router/index.d.ts export interface match<Params extends { [K in keyof Params]?: string } = {}> { params: Params; isExact: boolean; path: string; url: string; }
在动态路由 /other/1
中,props.match.url
的值为 /other/1
,props.match.path
的值为 /other/:id
。获取 props.match.params
中的属性仍然需要告诉 TS 有哪些属性。
import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; interface RouteParams { id: string } export default (props: RouteComponentProps<RouteParams>) => { return ( <div> 动态路由:{ props.match.params.id } </div> ) }
useRouteMatch 获取路由匹配信息
上面说到可以使用 props
获取到与路由相关的信息,其中包括了 match
、params
等,可以使用 props.match
获取路由的匹配信息。也可以使用 useRouteMatch
方法。
// @types/react-router/index.d.ts export function useRouteMatch<Params extends { [K in keyof Params]?: string } = {}>( path?: string | string[] | RouteProps, ): match<Params> | null;
注意 useRouteMatch()
的返回值可能是 null
,不能简单的通过 match.*
的形式访问。
// Other.tsx import React from 'react'; import { useRouteMatch } from 'react-router'; export default () => { const match = useRouteMatch(); return ( <div>路由路径:{ match && match.url }</div> ) }
useLocation
和 useHistory
的用法类似。
Switch
Switch
只会匹配子组件中的第一个路由组件。对于前面提到的,在不设置 exact
属性的前提下,/home
会同时匹配 /
和 /home
两个路由组件,使用 Switch
可以进行单一匹配,但与放置顺序也有关。
<Switch> <Route path="/home" component={ Home } /> <Route path="/" component={ Dashboard } /> </Switch>
Link
封装了 <a>
标签的组件进行路由跳转。
<Link to="/home">to home</Link>
NavLink
与 Link
的用法类似,会默认给当前路由路径与 to
属性匹配的组件添加 active
类名。
<NavLink to="/home">to home</NavLink> <NavLink exact to="/other">to other</NavLink> <NavLink to="/other/1">to other/1</NavLink>
当点击 to other/1
链接时,to other
链接也会被添加上 active
类名,这与 Router
组件是类似的,所以对于这样的导航,通常需要添加 exact
属性。
Redirect
to
属性进行重定向,通常会用在 Switch
中,作为匹配失败的处理。
编程式路由
useHistory()
返回的 history
对象,调用 push
方法。
参数传递
params
// 路由组件 <Route path="/home/:id" component={ Home }/> // Home.tsx interface RouteParams { id: string } export default () => { const params = useParams<RouteParams>(); return ( <div> { params.id } </div> ) } // Link 跳转 <Link to="/home/1">to home</Link> // history 跳转 import { useHistory } from 'react-router-dom'; export default () => { const history = useHistory(); const pushRouteParams = () => { history.push('/home/1') }; return ( <div> <Button onClick={ pushRouteParams }>to /home/1</Button> </div> ); };
state
// 路由组件 <Route path="/home" component={ Home }/> // Home.tsx import { useLocation } from 'react-router-dom'; export default () => { const location = useLocation(); return ( <div> { location.state && location.state.id } </div> ) } // Link 跳转 <Link to={{ pathname: '/home', state: { id: 1 } }}>to home</Link> // history 跳转 history.push({ pathname: '/home', state: { id: 1 } })
query
// @types/history export interface Location<S = LocationState> { pathname: Pathname; search: Search; state: S; hash: Hash; key?: LocationKey; }
location
对象没有 query
属性了,应该是不提供这个方法了吧……
push 和 replace
// Link <Link to="/home" /> <Link to="/home" replace/> // history history.push(...) history.replace(...)
钩子函数
v4 之后不再提供 onEnter
、onUpdate
和onLeave
等函数,而是在路由组件中分别对应 React 中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
等生命周期方法,这恰好就可以使用新特性 useEffect
进行替换了。
在路由组件内部使用 useEffect
,配合 history.replace()
进行路由权限控制
const history = useHistory(); const state = true; useEffect(() => { if (!state) { history.replace('/'); } });
也写成一个自定义 Hook
,在多个路由组件中使用
function useUserRole(state: boolean) { const history = useHistory(); useEffect(() => { if (!state) { history.replace('/'); } }); } useUserRole(false);
原文地址:https://segmentfault.com/a/1190000021001976
相关推荐
-
d3.js制作蜂巢图表带动画效果 javascript/jquery
2019-9-3
-
不懂 Nginx 的前端不是好前端 javascript/jquery
2020-6-11
-
前端中等算法-无重复字符的最长子串 javascript/jquery
2019-8-16
-
前端面试必备——异步(async) javascript/jquery
2020-5-26
-
js模拟iphone手势操作(拖拽、自动停靠) javascript/jquery
2019-1-3
-
html5全局属性 javascript/jquery
2019-9-13
-
谈谈JS中的函数劫持 javascript/jquery
2019-1-1
-
Flutter混合开发踩坑指北 javascript/jquery
2020-6-27
-
谈谈Web应用中的图片优化技巧及反思 javascript/jquery
2019-8-16
-
2020 年你应该知道的 React 库 javascript/jquery
2020-5-20