前言: css
路由放到前面说,同时也是我开始学习react最早想要搞懂的。由于咱们写的前端页面毕竟只有一个,随着业务增长,或者根据UI设计图,N个页面,驱动N个页面流通的即是<路由>不知道说法有没有问题,我的理解。毕竟不少文档讲到前端路由,都会从他的起源开始说。前端
至少,路由搞懂之后,对于以后页面的开发确定是有很大帮助的。本篇文章只讲解或者学习react路由的相关知识以及应用。优化方面在后期项目作完打包的时候再作详细调整。vue
优化这个好比vue有个路由懒加载模式,对应react确定也是有的【猜测】react
首先咱们须要了解下jsx 官方文档也有相关描述 如下摘自官方文档git
const element = <h1>Hello, world!</h1>;复制代码
这个有趣的标签语法既不是字符串也不是 HTML。github
它被称为 JSX,是一个 JavaScript 的语法扩展。咱们建议在 React 中配合使用 JSX,JSX 能够很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会令人联想到模版语言,但它具备 JavaScript 的所有功能。编程
JSX 能够生成 React “元素”。后端
Babel 会把 JSX 转译成一个名为 React.createElement()
函数调用。
api
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);复制代码
以上是彻底等效的两段代码,也就是说上面的写法最终编译成下面的一段代码,所以,你写的每一个页面都必须引入react浏览器
import React from 'react'
同时 React.createElement会预检查代码。若是你使用过githook 就会知道。
以前作vue会引入husky 这个就是用来预检查代码。他会检查如下几种: 我只能想起来这几种哈
1. xxxx is defined but not used 相似这个 就是定义了可是没使用过
2. === instead of == 就是说你必须使用三等
eg:
Line 2:8: 'logo' is defined but never used no-unused-vars
这个就要求你在写代码的时候就要注重你的代码质量。多余的或者写错的。复制代码
上篇文章有目录结构,对于初始化的react项目是没有router相关文件的,所以能够本身创建一个router文件夹/index.js 用来编写路由相关的,如下贴上路由文件相关配置
以上,是你能够在任何相关文章中能够找到的写法。下来就是要解读这些代码
前两句很简单是引入页面组件,。若是你写过vue熟悉vue的话,这个不是问题。即便你没有写过,也不要紧。
例如home页面中 class Home extends React.Component{} export default Home
对应 引入组件 就要用import 复制代码
关于react-router-dom 你能够查阅相关文档
www.jianshu.com/p/97e4af328…
顾名思义,路径会增长一个#的标识,这就是hash模式
HashRouter
组件,使用window.location.hash
和hashchange
事件构建路由。
Link
组件,会渲染一个a
标签;
<Link to={your path}> </Link>复制代码
用于渲染与路径匹配的第一个子 <Route>
或 <Redirect>
。
这与仅仅使用一系列 <Route>
有何不一样?
<Switch>
只会渲染一个路由。相反,仅仅定义一系列 <Route>
时,每个与路径匹配的 <Route>
都将包含在渲染范围内
<Route path="/home" component={home} /><Route path="/:value" component={value} />复制代码
对于以上代码,若是 访问 /home, 则会都匹配上。也就意味着这些都会被渲染。而咱们想要的是 他对应的那个组件渲染。这个时候就须要switch。
所以,这个笔者认为能够约定俗成,加上switch来控制咱们的路由复制代码
具体详情能够点击查看上述连接。该做者的文章讲解的比较详细。
import Home from '../page/home/home'import Article from '../page/article/article'import React from 'react'import { Route, Switch, HashRouter,withRouter } from 'react-router-dom'class Router extends React.Component { constructor(props) { super(props) this.state = { } } render() { return ( <HashRouter> <Switch> <Route exact path="/" component={withRouter(Home)} /> <Route exact path="/article" component={Article} /> </Switch> </HashRouter> ) }}export default Router复制代码
请仔细查看这段代码,与上述截图中。有一处是不一样的。
没错就是 withRouter 你可能不知道这个是用来作什么的。可是你确定能够在其余相关文章看到这样的字眼。接下来要详细解读下 withRouter做用
withRouter : 把不是经过路由切换过来的组件中,将react-router 的 history、location、match 三个对象传入props对象上
react中你能够经过 this.props来获取到路由相关参数。当你浏览器中控制台输出,就能够看到如下结果。
可是有一种状况你却没法获取到props的值。下面给出栗子
首先我建立了一个组件 是头部组件 header 用我以前整理好的目录,写于component中
接下来引入 app.js中
import React from 'react';import './App.css';import Router from './router/index'import Headers from './component/header/index';function App() { return ( <div className="App"> <Headers /> <Router /> </div> );}export default App;复制代码
以上我在header这个组件中 输出props 运行项目,你会发现控制输出的props是空的。
这就麻烦了,我头部会写N个标签来控制页面跳转的。天然而然少不了 标签的动态样式。
虽然用window.location能够监听到路由变化,可是我有强迫症,既然我要学习react,确定但愿能用react的语法来解决。所以这里就涉及到一个概念:
默认状况下必须是通过路由匹配渲染的组件才存在this.props,才拥有路由参数,
才能使用编程式导航的写法,执行this.props.history.push('/detail')跳转到对应路由的页面复制代码
以上这段话很清晰了,上述的header是一个公共组件,不是用路由控制匹配渲染的组件,所以props是空的。因而呢? react-router-dom给出了一种解决方案,即是withRouter
开头便写出了withRouter的做用
因而乎,改动header页面
import React from 'react'import {withRouter} from 'react-router-dom' // 引入withRouterclass Headers extends React.Component{ getProps() { console.log(this.props) console.log(window.location) } render() { return ( <div> 这是头部 {this.getProps()}</div> ) }}export default withRouter(Headers)复制代码
运行项目,???? 直接报错
Error: Invariant failed: You should not use <withRouter(Headers) /> outside a <Router>复制代码
因而又明白了一点: 这个withRouter 要 在router标签对里面 写。、可他是一个公共组件,又不能写在路由配置文件里。有没有一种办法能兼容这二者呢?
若是你使用过vue,必定很了解 插槽这个东西。他是用来干吗的,很简单,他是一个可定制化组件,这个组件能够渲染任何你写的内容。 方式是用<slot>
关于vue插槽,本篇不作详细解释,后续文章会作单独解读。
react是没有插槽概念的,可是他也提供了一个语法: this.props.children
请看如下示例:
class RootContent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div className='divider'>
{this.props.children}
</div>
);
}
}
class RootChild extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<RootContent>
<p>Hello, React</p>
<p>Hello, Redux</p>
<p>Hello, Facebook</p>
<p>Hello, Google</p>
</RootContent>
);
}
}
ReactDOM.render(
<RootChild />,
document.querySelector('#root')
);
本案例摘自“https://www.jianshu.com/p/ea4eaf32cd46” 笔者由于时间缘故就省略号这一块,用别人的案例来讲明复制代码
以上案例中,你就能够发现,<RootContent> 这个组件内写了一些内容,固然内容你能够随意改,他都会根据 <this.props.children> 渲染到页面中,这就是react‘插槽的使用方式’
依照这个,对个人项目从新作调整,如下只摘录了修改后的部分文件
笔者作个简单介绍:
// app.js
import React from "react";import "./App.css";import PropTypes from "prop-types";import routers from "./router/router.js";import { HashRouter, Route, Switch } from "react-router-dom";import Layout from "./component/layout/layout.js";const App = () => { return ( <HashRouter> <main> <Switch> <Layout>
/* react循环渲染 可查阅文档 */ {routers.map((item, index) => { return ( <Route path={item.path} exact={item.exact} component={item.component} key={index} /> ); })} </Layout> </Switch> </main> </HashRouter> );};export default App;复制代码
笔者对路由也作了进一步封装 下面代码摘自 router/index.js
import Home from "../page/home/home.js";import Articles from "../page/article/article.js";import ArticleDetail from "../page/articleDetail/articleDetail";const config = [ { path: "/", component: Home, exact: true, }, { path: "/articles", component: Articles, exact: true, }, { path: "/article/detail/:value", component: ArticleDetail, exact: true, },];// class RouteMap extends React.Component {// render() {// return (// <HashRouter>// <main>// <Switch>// <Route path="/" exact component={Home} />// <Route path="/home" exact component={Home} />// <Route path="/article" exact component={Articles}></Route>// </Switch>// </main>// </HashRouter>// )// }// }export default config;这么一来,路由配置页面就彻底只是定义路由的部分了,若是你写过vue的话,就会很明白了。
vue的就是相似如此的复制代码
下面摘录 layout
import React from "react";import "./index.scss";import Header from "../header/index";class Layout extends React.Component { render() { return ( <div className="home"> <div className="header"> <Header /> </div> <div className="main"> <div className="co">
/* this.props.children */ {this.props.children} </div> </div> </div> ); }}export default Layout;复制代码
完成以上的操做之后你就能够继续运行项目,此时你即可以在header中获取到 props的值了。你就能够对路由作出监听,从而定制化头部标签的动态样式了。
笔者的思路:
依照this.props.children的使用方法,笔者决定写一个组件layout,这个组件包含头部和内容两大模块 、
而内容是用路由匹配动态渲染的,可是考虑到后期页面若是增长了,太多,你不能写不少
<route>标签吧。因而采用react循环渲染的方式来调整路由。这么一来,原先的路由文件就真的只是路由定义了。、
到此,路由算是初步配置完成,同时也解决了 非路由匹配组件 没法获取props的问题
最后,笔者也是初步开始写做,写做水平不是很好。见谅。若是你以为对你有所帮助,麻烦关注点赞给个star吧。、
github.com/luoying122/…
项目会持续性写,持续性更新。直到完成先后端业务以及部署上线。该项目为个人我的技术博客。期待完成并公网访问的一天,愿与君共勉