React研習之旅(二):檢視控制器-路由

AndyLaw發表於2018-12-23

靜態路由or動態路由

宣告:此處的動態與靜態專指前端應用的開發領域。

路由是一種URL到頁面的對映關係.


靜態路由

靜態路由需要開發者考慮兩層:

  • 頁面的開發或元件和組合
  • URL路徑與元件關係的設定

靜態路由提前宣告,簡單易懂,Vue-router就是靜態路由的例子。

動態路由

動態路由相反,將上述兩層關注合為一體:頁面設計開發過程直接確立了URL與元件的關係,開發的樣子,決定了路由的樣子,符合了動態的理念。開發者無需額外管理與配置路徑。省心省力。

react-router v4採用了動態路由(react有一個靜態路由包在內測中),之前版本則是靜態路由,。 需要注意的是,react-router v4裡,route也是一種元件的存在形式.

對比一下,感受不同
//static routes
const routes = [
  {
    component: Root,
    routes: [
      {
        path: "/",
        exact: true,
        component: Home
      },
      {
        path: "/child/:id",
        component: Child,
        routes: [
          {
            path: "/child/:id/grand-child",
            component: GrandChild
          }
        ]
      }
    ]
  }
];
//dynamic routes
const App = () => (
  <Router>
    <div>
      <Header />

      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/topics" component={Topics} />
    </div>
  </Router>
);
export default App;
複製程式碼

react-router體系

到react-router的github官網看到這一句:

we actually publish several packages to npm from the same codebase. 同一個程式碼基專案釋出了幾個包:

在這裡插入圖片描述
有幾個資訊:

  • react-router為核心包,其他包依賴該包
  • 開發web專案使用react-router-dom,開發原生應用使用react-router-native
  • 靜態路由版本react-router-config,目前內測階段

因此我們只需要關注react-router-dom即可。

react-router-dom的幾個核心概念

react-router-dom教程網上很多,在此我們羅列幾個比較重要或易錯的概念,如果需要詳細內容,請至:官方API


BrowserRouter 與 HashRouter

有兩種路由型別:browserRouter、HashRouter

// <BrowserRouter>
http://example.com/about

// <HashRouter>
http://example.com/#/about
複製程式碼

前者使用 HTML5 History API 來跟蹤路由變化。後者使用window.location.hash作為記錄跟蹤方式 。

前者新穎美觀,需要服務端的額外支援,原理就是攔截前端的路徑請求(非功能請求),響應同一個index.html,然後瀏覽器會根據根據路徑渲染相應的檢視或頁面。舉個express的例子:

const express = require('express');
const path = require('path');
const port = process.env.PORT || 8080;
const app = express();

//載入靜態資源,dist下放build好的檔案
app.use(express.static(__dirname + '/dist'))

//非功能請求統一轉到index.html
//index.html及其對應的js檔案會根據React-Router規則匹配對應route
app.get('*', function (request, response){
  response.sendFile(path.resolve(__dirname, 'dist', 'index.html'))
})

app.listen(port, function () {
  console.log("server started on port " + port)
})
複製程式碼

後者簡單相容性好,不需要額外配置服務端。 需要指出的是:rowserRouter或 HashRouter必須位於路由相關元件的最外層,此處的相關元件常用的有:Link、Route、Switch、Redirect

路由的導航方式
  • 宣告式導航:<Link to/>標籤,或<a href="#"></a>標籤,或<Redirect to/>
  • 程式設計式導航(history方法呼叫,需要通過):push(path)、replace(path)、go(n) 、goBack() 、 goForward()
  • withRouter高階元件,實現程式設計導航必須藉助withRouter高階元件
檢視/元件的配置方式

都是通過Route元件這座橋樑實施的,但有多種實施方式render、component、children

  • render只能為函式元件,匿名、不匿名皆可.
  • children可為函式元件、jsx物件
  • component可為函式元件或class元件

不好理解?程式碼演示對比下

function fnComponent(){
	return <div>我是個具名函式元件</div>
}
class classComponent extends Component{
	render(){
		<div>我是個class元件</div>
	}
}
//render只能為函式元件
<Route path="/render" render={()=>{<div>我是個匿名/行內函式元件</div>}}/>
<Route path="/render" render={fnComponent}/>

//children可以為函式元件、也可是jsx物件
<Route path="/children" children={()=>{<div>我是個匿名/行內函式元件</div>}}/>
<Route path="/children" children={fnComponent}/>
<Route path="/children" children={<div>我是一條jsx語法標籤物件</div>}/>

//component只能為函式元件或class元件
<Route path="/children" component={()=>{<div>我是個匿名/行內函式元件</div>}}/>
<Route path="/children" component={fnComponent}/>
<Route path="/children" component={classComponent }/>
複製程式碼

注意官方有這句提示: if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop . 翻譯就是:行內函式(匿名函式)作為component屬性傳遞(prop)時,會在每次渲染時建立一個react元素,這將重新掛載(mount)元件,而不是在既存的基礎上更新。

這很好理解,匿名函式飄忽不定,每次render都意味著props的改變。如果實在用匿名函式,請選擇children或render的方式


再來張思維導圖

路由思維導圖


小結

本文介紹了React-router的一些概念,談了動態靜態路由,react-router的體系,兩種路由模式,導航方式、檢視元件配置方式,內容有深有淺,紕漏在所難免,不足之處望讀者朋友們留言或指正,謝謝!。

下一篇我們會介紹React的打包相關

相關文章