前言:
路由放到前面说,同时也是我开始学习react最先想要搞懂的。因为我们写的前端页面毕竟只有一个,随着业务增加,或者根据UI设计图,N个页面,驱动N个页面流通的便是<路由>不知道说法有没有问题,个人理解。毕竟很多文档讲到前端路由,都会从他的起源开始说。
至少,路由搞懂以后,对于之后页面的开发肯定是有很大帮助的。本篇文章只讲解或者学习react路由的相关知识以及应用。优化方面在后期项目做完打包的时候再做详细调整。
优化这个比如vue有个路由懒加载模式,对应react肯定也是有的【猜想】
简单介绍jsx语法
首先我们需要了解下jsx 官方文档也有相关描述 以下摘自官方文档
const element = <h1>Hello, world!</h1>;这个有趣的标签语法既不是字符串也不是 HTML。
它被称为 JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
JSX 可以生成 React “元素”。
JSX 表示对象
Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );
以上是完全等效的两段代码,也就是说上面的写法最终编译成下面的一段代码,因此,你写的每个页面都必须引入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 如何 使用路由
上篇文章有目录结构,对于初始化的react项目是没有router相关文件的,因此可以自己建立一个router文件夹/index.js 用来编写路由相关的,以下贴上路由文件相关配置
以上,是你可以在任何相关文章中可以找到的写法。下来就是要解读这些代码
关键字眼: react-router-dom
前两句很简单是引入页面组件,。如果你写过vue熟悉vue的话,这个不是问题。即使你没有写过,也没关系。
例如home页面中 class Home extends React.Component{} export default Home
对应 引入组件 就要用import 关于react-router-dom 你可以查阅相关文档
www.jianshu.com/p/97e4af328…
React-router
React-router提供了一些router的核心api,包括Router, Route, Switch等,但是它没有提供dom操作进行跳转的api。React-router-dom
React-router-dom提供了BrowserRouter, Route, Link,hashRouter,withRouter等api,我们可以通过dom的事件控制路由。所以在开发过程中,我们更多是使用React-router-dom。hashRouter
顾名思义,路径会增加一个#的标识,这就是hash模式
HashRouter组件,使用window.location.hash和hashchange事件构建路由。
Link
Link组件,会渲染一个a标签;
<Link to={your path}> </Link>Switch
用于渲染与路径匹配的第一个子 <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
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'
// 引入withRouter
class 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/…
项目会持续性写,持续性更新。直到完成前后端业务以及部署上线。该项目为我的个人技术博客。期待完成并公网访问的一天,愿与君共勉