在这一小节,我们将学习到最重要的两部分核心内容
- react-router路由
- react-redux状态管理,类似于vuex
- 这两个东西都是非常的重要的东西
react-router
与vue-router一样,react中也是有router的,接下来我们来学习看看这个到底是怎么操作的
基础的使用
基础的使用非常的简单,我们使用官方推荐的一个库,来进行路由管理
- react-router 核心组件
- react-router-dom 应用于浏览器端的路由库(单独使用包含了react-router的核心部分)
- react-router-native 应用于native端的路由
yarn add react-router-dom# 或者,不使用 yarnnpm install react-router-dom
- 由于最新的react-router更新了,所以不再需要单独的配置
- Router是所有路由组件共用的底层接口组件,它是路由规则制定的最外层的容器。
- Route路由规则匹配,并显示当前的规则对应的组件。
- Link路由跳转的组件

小结:如果说我们的应用程序是一座小城的话,那么Route就是一座座带有门牌号的建筑物,而Link就代表了到某个建筑物的路线。有了路线和目的地,那么就缺一位老司机了,没错Router就是这个老司机。
安装完毕之后我们来使用一下
导入三个核心的东西,注意啊我们这里是起别名的

使用Router组件包裹整个应用

- 使用link作为点击跳转的(入口)

- 使用Route配置(出口)

注意啊,这里的这个这个path就是配置的,component就是指定匹配的时候要显示的路由,link的to和Route的path是要匹配的
常用组件的说明
- 一个React应用中只需要使用一次,除了我们之前说的BrowserRouer我们还有一个HashRouter效果是一样的,只是后面加了一个#符号
- Link最终变成a标签,href就变成了to的属性,to也是url里的东西,也是可以更改的,
- Route是出口,占位符,path是一个规则,注意如果有一堆Router那么一个Link会去匹配所有的Route的paht直到找到匹配成功为止
整个流程到底是什么呢?
只要rul发生变化,整个路由都会重新匹配一次
如何实现编程式导航?
非常的简单,我们之前说过React中的prop是一个核心,如果一个组件是被Route占位显示出来的,意味着这个组件内部的prop上就有一个history属性,通过它就能完成url改变 ,实现导航

history有相关的如下的一些api
默认的路由如何展示?展示还是非常的简单
只需要使用一个path = ‘/‘就好了。/就是默认的路由,进入页面就会被匹配的路由,
精确匹配
以上都是最基础的使用步骤,当然关关是基础的使用是远远不足够我们做项目的,我们需要更多的深入学习react-router
如何实现路由的参数传递呢?
比如,你点击某一个具体的文件的时候 ,我需要你这篇文章的id那么你如何传递这个id给我呢?我又要如何获取?props.params 是一种解决方案
1、目录及 组件关系图
2、源码
./index.js
import React from 'react';import ReactDOM from 'react-dom';import App from './components/App/App';ReactDOM.render(<App />, document.getElementById('root'));
./src/components/App/App.js
import React , { Component } from 'react';import { BrowserRouter as Router, Route, Link } from 'react-router-dom';import About from '../About/About';class App extends Component {constructor() {super();this.state = {lists: ['10010', '10086', '8000'], // 在react中万物皆组件,万物皆组件,跟我默念,万物皆组件!!!!!};}render() {let linkList = this.state.lists.map(item => {return (<li><Link to={`/about/${item}`}> {item} </Link></li>);});return (<Router><div><ul> { linkList } </ul><Route path="/about/:tel" component={About} /></div></Router>);}}export default App;

注:< Route>在选择渲染About组件时,其实也传给了About组件一个 match对象。在About中直接this.props.match即可访问。
这句话的意思就是,在路由跳转的时候,你传递了一个match对象在props上,这个match就是路由对象
./src/components/About/About.js
import React, { Component } from 'react';class About extends Component {render() {return (<div>about: {this.props.match.params.tel}</div>);}}export default About;


点击8000后:
第二种传参扥方式
使用query定义传值方式,注意:页面刷新后,参数丢失
<Route path="/query" component={App} />//在Link组件中定义参数const param ={pathname:"/query",query:"参数"}<Link to={param}>List</Link>//在子组件中获取参数值this.props.location.query
第三种解决方案
以上仅仅是我们的点击的时候传递的值,在rul上可以拿到,但是如果我们要编程式导航,那么如何拿到我们的值呢?
- 入股是history.repacle( 目标path,{})第二个就是你需要传递过去的对象,在目标path组件内通过this.props上有一个location能拿到第二个对象(你传递过去的值)
第四中解决方案(推荐)
可以有效的解决页面刷新后,参数丢失的问题
linke定义
let obj = {pathname: '/component',search: '?sort=name',query: { fromDashboard: 123 },state: { fromDashboard: 123 }}<Link to="{obj}">Zillow Group</Link>
接收
this.props.location.search // search == "?sort=name"this.props.location.query // query == { fromDashboard: 123 }this.props.location.state // state == { fromDashboard: 123 }
如何实现多层级的页面嵌套呢?实际上也非常的简单
1、目录及 组件关系图
2、源码
./index.js
import React from 'react';import ReactDOM from 'react-dom';import App from './components/App/App';ReactDOM.render(<App />, document.getElementById('root'));
./src/components/App/App.js
import React from 'react';import { BrowserRouter as Router, Route, Link } from 'react-router-dom';import Home from '../Home/Home';import About from '../About/About';import Inbox from '../Inbox/Inbox';function App() {return (<Router><div><ul><li><Link to="/">Home</Link></li><li><Link to="/about">About</Link></li><li><Link to="/inbox">Inbox</Link></li></ul><hr/><Route path="/" exact component={Home} /><Route path="/about" component={About} /><Route path="/inbox" component={Inbox} /></div></Router>);}export default App;

./src/components/About/About.js
import React, { Component } from 'react';class About extends Component {render() {return (<div>i am about</div>);}}export default About;
./src/components/Inbox/Inbox.js
import React, { Component } from 'react';import { BrowserRouter as Router, Route, Link } from 'react-router-dom';class Inbox extends Component {render() {return (<div><h2>Inbox title</h2><ul><li><Link to={`${this.props.match.url}/components`}> Components </Link></li><li><Link to={`${this.props.match.url}/props-v-state`}> Props v. State </Link></li></ul><Route path={`${this.props.match.path}/:getId`} component={Topic} /><Route path={this.props.match.path} exact render={() => <h3>Please select a topic.</h3>}/></div>);}}function Topic(props) {return <h3>{props.match.params.getId}</h3>;}export default Inbox;
3、展示

点击Inbox后:
点击 Props v. State 后:
如何把路由独立出来?(手写实现,当然你也可以使用router-config这个来搞)
目前啊,我发现现在的router耦合度太高了,如果我想要把他们我说的是router独立出来操作,那么我要如何做呢? 实际上还是有些复杂的,我们来看需求
需求,我希望
import home from 'pages/Home.jsx'import record from 'pages/Record.jsx'import feedBack from 'pages/FeedBack.jsx'const router = [{path:'/record',component:record},{path:'/',component:home,redirect:'/feedBack',children:[{path:'/feedBack', ////就是这里vue的话会写成feedBack,但是react会/component:feedBack}]},]//如果熟悉vue的小伙伴会明白想干什么,// 主要是在/路径下生成home但是匹配到/之后会重新定义到/feedBack路径上去,//此时的home和feedBack组件是共存的,也就是常说的layout和contain是共存的,如果是vue的话很简单,很好做,但是react的路由我*****
实现的步骤如下
我们使用了router 对路由数据进行了构建,下面我只需要一个方法生成他,手写!但是没有必要,我们后续会介绍一个router结合使用的一个库,利用那个库,可以优雅的实现动态路由生成
// 生成动态路由的方法function generateRoute(value){if(value.children){ // 如果有子组件return (<Switch key={value.path}><Redirect exact from={value.path} to={value.redirect} /><Route key={value.path} path={value.path}><value.component>{value.children.map(item=>{return generateRoute(item)})}</value.component></Route></Switch>)}// 如果没有子组件return <Route key={value.path} path={value.path} component={value.component} />}// 组件function app(){return (<Switch>{// 重点来了!router.map(item=>{return generateRoute(item)})}</Switch>)}// 在一系列的转化下他会生成这个东西<Switch><Route path='/record' component={record}></Route><Switch><Redirect exact from='/' to='/feedBack'></Redirect><Route path='/'><Home>{<Route path='/feedBack' component={feedBack} />}</Home></Route></Switch></Switch>//在这里我们看到了<Home>组件,这样在Home组件中我们可以通过this.props.children来获取传入的组件,类似于vue的插槽
相关技术点说明:
在上述的例子中,我们的这个发现有两个貌似没有接触过的东西Switch 和Redirect接下来我们来看看他们到底是干什么用的
- switch
字面上非常好理解,这个就是一个开关,同一个时间点内只匹配一个
有
- reditect
字面上非常好理解,重定向!,这个没有什么需要说明的,重定向!重什么地方跳到什么地方去
<Redirect from="messages/:id" to="/messages/:id" />
使用第三方库来实现 路由的配置抽离
在vue中,经常会有 路由拦截件的东西,在react中如何做到呢? 答案就是
react-router-config
npm i react-router-dom react-router-config –save
- react可以通过一款react-router-config插件做到和vue-router一样的使用块感
- 搞一个home页面 ```javascript import React from ‘react’;
export default function Home(){ return (
) }
- 建立一个about页面```javascriptimport React from 'react';import {Link} from 'react-router-dom';import {renderRoutes} from 'react-router-config';//变量的导出用export,而不是export defaultexport const About = (props)=>{const route = props.routereturn (<div><h1>这是关于</h1><a href="/">去home</a><a href="/discover">去discover</a><Link to="/about/my">关于我的</Link><br /><Link to="/about/you">关于你的</Link>{/*使用renderRoutes方法继续渲染子路由,第二个参数可以进行传参*/}{renderRoutes(route.childrens,{user:'hello'})}</div>)}
- 建立一个discover页面 ```javascript import React from ‘react’; import {Link} from ‘react-router-dom’; import {renderRoutes} from ‘react-router-config’;
export default function Discover(props){
const route = props.route
return (
- 再建立两个子页面my```javascriptimport React from 'react';export default function My(props){return (<div><h1>这是关于我的</h1><p>{props.user}</p></div>)}
you
import React from 'react';export default function You(){return (<div><h1>这是关于你的</h1></div>)}
- 我们还需要一些辅助页面
Star
import React from 'react';export default function Star(){return (<div><h1>这是发现星星</h1></div>)}
Earth
import React from 'react';//<p>{props.match.params.id}</p>export default function Earth(props){return (<div><h1>这是发现地球</h1></div>)}
- 建立配置文件
router.js
在src目录下新建文件夹route(名字自己随便取),然后在该目录下新建route.js文件,在route.js里进行文件的配置import Home from '../component/home'//注意非函数、非表达式等导入要用{}括住import {About} from '../component/about'import Discover from '../component/discover'import Earth from '../component/earth'import Star from '../component/star'import My from '../component/my'import You from '../component/you'const routes = [{path:'/',component: Home,exact:true},{path:'/about',component: About,childrens:[{path:'/about/my',component:My},{path:'/about/you',component:You}]},{path:'/discover',component: Discover,childrens:[{path:'/discover/earth',component:Earth},{path:'/discover/star',component:Star}]}]export {routes}
- 最后的最后我们总算来渲染了
index,js
import React from 'react';import ReactDOM from 'react-dom';import * as serviceWorker from './serviceWorker';import { BrowserRouter} from "react-router-dom";import { renderRoutes } from "react-router-config";import './index.css';import {routes} from './router/route';// 使用renderRoutes方法渲染路由ReactDOM.render(<BrowserRouter>{ renderRoutes(routes) }</BrowserRouter>, document.getElementById('root'));serviceWorker.unregister();
以上就是一个非常简单的库的基础使用在里面
如何做路由守卫的拦截和权限的判断呢?
非常简单,使用router-config只需要改一些东西就好,什么?💩吧,这要手写一个鉴权 ,没事哥扛得住!
由于这里的这一块内容相对的比较难,需要学习redux之后才能读得明白,那么我们先去学习redux后续回过头开看这个实现的技术解决方案
关于路由鉴权和动态路由匹配的这个问题是非常值得一提的,因为在业务中会经常的使用到,所以啊,这个非常的重要!我们在学习完redux之后需要额外的认真学习,该需求的解决方案


