有时候会需要使用编程式导航,比如上方导航栏里面选项,响应按钮事件,进行路由跳转。react 的做法是通过高阶函数,函数体内部向组件的 props 注册一些路由的方法,最后返回一个新的组件。
下面是一个结合 TypeScript 使用 withRouter 的例子:
interface NavigationState {routes: Array<{path: string;name: string;key: string;}>;selectedKey: string;}interface NavigationProps {name: string;}class Navigation extends Component<RouteComponentProps & NavigationProps, // 使用「交叉类型」来处理Props的关系NavigationState> {state = {routes: [],selectedKey: "1"};toggleRoute = (event: ClickParam) => {this.props.history.push(path); // route的方法已经被注册到了Props上};render() {// ...);}}export default withRouter(Navigation);
exact
已经关闭了模糊匹配。那么strict
设置为true
(默认是false
),会有什么区别呢。例如 path 为 /a
的时候:
true
:不匹配/a/
,只匹配/a
/a/
和/a
均匹配可以直接使用 react-router-config 组件,实现原理:
import { Route, Switch, SwitchProps, RouteProps } from "react-router-dom";function renderRoutes(params: {routes: RouteProps[];switchProps?: SwitchProps;}) {const { switchProps, routes } = params;return (<Switch {...switchProps}>{routes.map((route, index) => (<Routekey={index}path={route.path}component={route.component}exact={route.exact || true}strict={route.strict || false}></Route>))}</Switch>);}
假设我们的路由如下:
import { RouteProps } from "react-router-dom";const config: RouteProps[] = [{path: "/",component: HomePage},{path: "/user",component: UserPage}];
在 VueJS 技术栈中,vue-router 是提供路由响应的钩子函数,例如:beforeEach
、afterEach
等等。
但是在 React 中,react-router 并不提供相关的钩子函数。那么如果有顶部导航栏,不同页面切换时,高亮不同的标签,那么应该怎么实现响应路由变化呢?
首先即使是路由,在 React 中,它也是一个组件对象。因此,如果要更新试图,必须触发组件的 render。而触发组件的关键在于,props 发生改变。
第一步:需要使用withRouter
来包装对应的组件,将路由的信息作为 props 注入组件,比如顶部导航栏。
第二步:下面是 React17 前后的简单例子。
React17 之前:
import { withRouter, RouteComponentProps } from "react-router-dom";class Navigation extends Component<RouteComponentProps, any> {state = {selectedPath: "/"};// 在componentWillReceiveProps中接受新的props// 决定是否更新statecomponentWillReceiveProps(nextProps: RouteComponentProps) {if (nextProps.location.pathname === this.props.location.pathname) {this.setState({ selectedPath: nextProps.location.pathname });}}render() {// 这里的render渲染,取决于state是否更新const { selectedPath } = this.state;return <div>导航栏选中信息:{selectedPath}</div>;}}export default withRouter(Navigation);
在 React17 之后,不推荐使用componentWillReceiveProps
等不确定的生命周期。处理的思路是:render 函数返回的视图中,变量的变化依赖 props 属性的值。
import { withRouter, RouteComponentProps } from "react-router-dom";class Navigation extends Component<RouteComponentProps, any> {state = {paths: ["/", "/a"]};render() {const { pathname } = this.props.location;const { paths } = this.state;let selectedPath = "";paths.some(path => {if (path === pathname) {selectedPath = path;return true;}return false;});return <div>导航栏选中信息:{selectedPath}</div>;}}export default withRouter(Navigation);