react学习总结(二):关于react路由那些事儿

前言: css

路由放到前面说,同时也是我开始学习react最早想要搞懂的。由于咱们写的前端页面毕竟只有一个,随着业务增长,或者根据UI设计图,N个页面,驱动N个页面流通的即是<路由>不知道说法有没有问题,我的理解。毕竟不少文档讲到前端路由,都会从他的起源开始说。前端

至少,路由搞懂之后,对于以后页面的开发确定是有很大帮助的。本篇文章只讲解或者学习react路由的相关知识以及应用。优化方面在后期项目作完打包的时候再作详细调整。vue

优化这个好比vue有个路由懒加载模式,对应react确定也是有的【猜测】react

简单介绍jsx语法

首先咱们须要了解下jsx 官方文档也有相关描述 如下摘自官方文档git


const element = <h1>Hello, world!</h1>;复制代码

这个有趣的标签语法既不是字符串也不是 HTML。github

它被称为 JSX,是一个 JavaScript 的语法扩展。咱们建议在 React 中配合使用 JSX,JSX 能够很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会令人联想到模版语言,但它具备 JavaScript 的所有功能。编程

JSX 能够生成 React “元素”。后端

JSX 表示对象

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
api

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.hashhashchange事件构建路由。


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'  // 引入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/…

项目会持续性写,持续性更新。直到完成先后端业务以及部署上线。该项目为个人我的技术博客。期待完成并公网访问的一天,愿与君共勉

相关文章
相关标签/搜索