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/…

項目會持續性寫,持續性更新。直到完成先後端業務以及部署上線。該項目爲個人我的技術博客。期待完成並公網訪問的一天,願與君共勉

相關文章
相關標籤/搜索