💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] [API地址:react-router.docschina.org](https://react-router.docschina.org/) # react-route 官网:https://reactrouter.com/web/guides/quick-start React Router 4.0 (以下简称 RR4)它遵循 React 的设计理念,即万物皆组件。 所以 RR4 只是一堆 提供了导航功能的组件(还有若干对象和方法),具有声明式(**声明式编程**简单来讲就是你只需要关心做什么,而无需关心如何去做,好比你写 React 组件,只需要 render 出你想要的组件,至于组件是如何实现的是 React 要处理的事情。),可组合性的特点。 React Router V4 相对 V2/V3 几乎完全重写了,遵循 Just Component 的 API 设计理念。 | Package | Package | Docs | Description | | --- | --- |--- |--- | | [`react-router`](https://github.com/ReactTraining/react-router/blob/master/packages/react-router) | npm-v5.2.0 | [API Docs-site](https://reacttraining.com/react-router/core/guides/quick-start) | The core of React Router | | [`react-router-dom`](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom) | npm-v5.2.0 | [API Docs-site](https://reacttraining.com/react-router/web/guides/quick-start) | DOM bindings for React Router | | [`react-router-native`](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-native) | npm-v5.2.0 | [API Docs-site](https://reacttraining.com/react-router/native/guides/quick-start) | [React Native](https://facebook.github.io/react-native/) bindings for React Router | | [`react-router-config`](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-config) | npm-v5.1.1 | [API Docs-readme](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-config/#readme) | Static route config helpers | ## react-router 还是 react-router-dom? 在 React 的使用中,我们一般要引入两个包,`react` 和 `react-dom`,那么 `react-router` 和 `react-router-dom` 是不是两个都要引用呢? 非也,坑就在这里。 1. React-router React-router 提供了一些 router 的核心 api,包括 `Router`, `Route`, `Switch`等,但是它没有提供 dom 操作进行跳转的 api , **服务器端渲染**很适合。 2. react-router-dom `React-router-dom` 提供了`BrowserRouter`,`HashRouter`,`Link`等等在 web 端常用的 DOM 类组件,我们可以通过 dom 的事件控制路由。例如点击一个按钮进行跳转,大多数情况下我们是这种情况,所以在开发过程中,我们更多是使用 React-router-dom。 两个只要引用一个就行了,因此我们只需引用 `react-router-dom` 这个包就行了。当然,如果搭配 redux ,你还需要使用 `react-router-redux`。 [what is the diff between react-router-dom & react-router?](https://github.com/ReactTraining/react-router/issues/4648) # react-router v5 v5 中最重要的改进是对 >= 15 版本的 React 完全兼容,并对 React 16 提供了更好的支持。 升级了 React 的 context API;消除了所有 <StrictMode> 警告;对捆绑基础架构进行了彻底检查,并对发布的所有绑定包进行了全面测试。 还为生产引入了预优化的 build,可以不用在构建脚本中手动将 `process.env.NODE_ENV` 设置为`production`,更重要的是不会将路由器构建为 build 的一部分,团队已经在开发和生产模式中处理了这个问题。 导入方式也因此需要改变: ``` // Instead of: import Router from 'react-router/Router'; import Switch from 'react-router/Switch'; // do: import { Router, Switch } from 'react-router'; ``` 目前仍然支持前一种风格,但会发出警告。 此外,v5 简化并自动化了发布过程,从现在开始能够更频繁、更可预测地发布。 新特性方面,此版本的一个主要新功能是能够在 <Route path> 中使用数组,简化了操作: ``` // Instead of this: <Switch> <Route path="/users/:id" component={User} /> <Route path="/profile/:id" component={User} /> </Switch> // you can now do this: <Route path={["/users/:id", "/profile/:id"]} component={User} /> ``` 还带来了一些 bug 修复,包括支持 <Link innerRef> 中的 `React.createRef`,并支持在 `<Route component>` 中使用 `React.forwardRef`。 > 详情查看发布公告 > https://reacttraining.com/blog/react-router-v5/ # 详解 现在改版之后,我们引入的包是 `react-router-dom` 包。 改版之后的 `react-router-dom` 路由,我们要理解三个概念,`Router`、`Route`和`Link`。 ## `<Router>` `<Router>` 是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由: * `<BrowserRouter>`:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步;url 是这样的:`/user/liuna` * `<HashRouter>`:使用 URL 的 hash (例如:`window.location.hash`) 来保持 UI 和 URL 的同步; url 是这样的:`/#/user/liuna?\_k=adseis` * `<MemoryRouter>`:能在内存保存你 “URL” 的历史纪录 (并没有对地址栏读写);可以被用在任何可以运行 js 的环境中;通常被用来做单元测试(没有浏览器环境);自己维护一个 location array的。 * `<StaticRouter>`:从不会改变地址; 使用方式: ``` import { BrowserRouter as Router } from "react-router-dom"; class Main extends Component{ render(){ return( <Router> <div> // Router 组件有且只有一个根节点 //otherCoding </div> </Router> ) } } ``` ## `<Link>` Link是 react 路由中的点击切换到哪一个组件的链接,(这里之所以不说是页面,而是说组件,因为切换到另一个界面只是展示效果,react 的本质还是一个单页面应用-single page application)。 基本使用方式: ```js import { BrowserRouter as Router, Link} from "react-router-dom"; class Main extends Component{ render(){ return( <Router> <div> <ul> <li><link to='/'>首页</Link></li> <li><link to='/other'>其他页</Link></li> </ul> </div> </Router> ) } } ``` 特别说明: 第一、`<Router>` 下面只能包含一个盒子标签,类似这里的div。  第二、`<Link>` 代表一个链接,在 html 界面中会解析成 a 标签。作为一个链接,必须有一个 to 属性,代表链接地址。这个链接地址是一个相对路径。  第三、`<Route>`,是下面要说的组件,有一个 path 属性和一个组件属性(可以是 component、render 等等)。 ## `<Route>`  * `Route` 代表了你的路由界面,`path` 代表路径,`component` 代表路径所对应的界面。 * 在其 `path` 属性与某个 `location` 匹配时呈现一些 UI (`component`)。 使用方式: ``` import React,{ Component } from "react"; import { render } from "react-dom"; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; // home.js class Home extends Component{ render(){ return ( <div>this a Home page</div> ) } } // other.js class Other extends Component{ render(){ return ( <div>this a Other page</div> ) } } // app.js class Main extends Component{ render(){ return ( <Router> <div> <ul> // 除了路由组件,可以写入其他标签,默认 Route 所在的位置为路由组件显示的容器 <li><Link to="/home">首页</Link></li> //(tips:Link写在Router内部形成路由结构) <li><Link to="/other">其他页</Link></li> </ul> <Route path="/home" component={Home}/> <Route path="/other" component={Other}/> </div> </Router> ) } } render(<Main />,document.getElementById("root")); ``` ## `<Switch>` 用于渲染与路径匹配的第一个子`<Route>`或`<Redirect>`。 ~~~ import { Switch, Route } from 'react-router'; <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/:user" component={User} /> <Route component={NoMatch} /> </Switch> ~~~ 现在,当我们在 `/about` 路径时,`<Switch>` 将开始寻找匹配的 `<Route>`。我们知道,`<Route path="/about" />` 将会被正确匹配,这时 `<Switch>` 会停止查找匹配项并立即呈现 `<About>`。同样,如果我们在 `/michael` 路径时,那么 `<User>` 会呈现。 ## `<Redirect>` 通过 `Redirect` 组件对象,设置 `to` 属性 ``` <Redirect to {{ pathname: '/about', search: '?utm=something', state: { referrer: someplage.com } }}> ``` ## 路由参数传递 ```     /a/1 ---this.props.match.params.id     /a?id=1---this.props.location.query.id ``` ## 路由切换跳转 ```     this.props.history.push({ pathname: '/detail', state: { id: 3 } }) .... this.props.history.location.state // 获取 传过来的参数 ```     因为 BrowserRouter  相当于 `<Router history={history}>` 故可直接通过 history 进行 `push` 跳转 ## withRouter [`withRouter`](https://reactrouter.com/web/api/withRouter) 是`react-router-dom`中的一个高阶组件 ,要先引入才能使用: ``` import { BrowserRouter as Router, Route, Link, Switch, withRouter, RouteComponentProps } from 'react-router-dom' ``` 使用高阶组件时有两种方法: 1⃣️函数式调用: ``` // @ts-ignore export default withRouter(SystemSider) ``` 2⃣️装饰器: ``` // @ts-ignore @withRouter ``` 正常情况下 只有 Router 组件能够自动带有三个属性 如下的 Home 组件有 ``` var Home = ( {history,location,match})=> <div>{location.pathname}</div> <Route exact path="/Home" component={Home}/> ``` `withRouter`作用是将一个组件包裹进 Route 里面,然后 react-router 的三个对象`history`, `location`, `match`就会被放进这个组件的`props` 性中。 ``` import React from 'react'; import { connect } from 'dva'; import styles from './nav.css'; import { Route, Switch, routerRedux,withRouter } from 'dva/router'; // dva写法 // import { withRouter } from 'react-router-dom'; // 普通react项目写法 class Nav extends React.Component { jumping() {//跳转到 this.props.history.push('/') console.log(this.props) } render() { const { match, location, history } = this.props; return ( <div className={styles.box}> <div className={styles.navBox}> <div className={styles.iconBox}> <div className={styles.title}>公路地质灾害时空数据监测预警系统</div> </div> <div>You are now at {location.pathname}</div> <div className={styles.listItem} onClick={this.jumping.bind(this)}>动态多维可视化子系统</div> </div> </div> </div> ); } } export default withRouter(Nav); ``` `这个`例子中点击`div`利用`history`跳转到别的页面。使用`withRouter`后,`this.props`里才会有`history`属性。 `withRouter` 的作用就是,但是我们要点击某个元素去跳转一个页面,比如点击页面的 logo 返回首页,这时候就可以使用 `withRouter` 来做. ## 其他函数 ### `replace` 有些场景下,重复使用 `push` 或 `a` 标签跳转会产生死循环,为了避免这种情况出现,react-router-dom 提供了`replace`。在可能会出现死循环的地方使用 `replace` 来跳转: ``` this.props.history.replace('/detail'); ``` ### `goBack` 场景中需要返回上级页面的时候使用: ``` this.props.history.goBack(); ``` # react-router-redux https://segmentfault.com/q/1010000010489394 react-router-redux 是将 react-router 和 redux 集成到一起的库,让你可以用 redux 的方式去操作 react-router。 例如,react-router 中跳转需要调用 `router.push(path)`,集成了 react-router-redux 你就可以通过 `dispatch` 的方式使用 router,例如跳转可以这样做 `store.dispatch(push(url))`。 本质上,是把 react-router 自己维护的状态,例如 location、history、path 等等,也交给 redux 管理。一般情况下,是没有必要使用这个库的。 # 示例 [How To Create A Multi-Page Website With React In 5 Minutes]( https://www.techomoro.com/how-to-create-a-multi-page-website-with-react-in-5-minutes/) [techomoro/ReactMultiPageWebsite](https://github.com/techomoro/ReactMultiPageWebsite) https://www.kirupa.com/react/creating_single_page_app_react_using_react_router.htm # 参考 [React Router:从V2/V3迁移到V4 ](https://github.com/YutHelloWorld/Blog/issues/4) [react-router V4 中三种 router 区别?](https://www.zhihu.com/question/63662664) [H5 history API 解析](https://www.jianshu.com/p/daf1c1b93c5c/) [性能 & 集成 —— History API](https://juejin.im/post/5c5313905188257a4a7fbeab#heading-9) [Router5](https://router5.js.org/)