React-router 初學(xué)者的14個(gè)lessons

Lesson1
1、首先確保安裝了Node.js和npm依賴包管理工具
2、在git上克隆官方示例程序

git clone https://github.com/reactjs/react-router-tutorial

cd react-router-tutorial

cd lessons/01-setting-up

npm install

npm start

運(yùn)行完成后打開(kāi):http://localhost:8080
就可以在瀏覽器看見(jiàn): "Hello React Router"
打開(kāi)modules/App.js,更改里面內(nèi)容,可以看到瀏覽器上的內(nèi)容隨時(shí)變化!

Lesson2 : rendering a router
1、打開(kāi)index.js
首先import Router、Route和hashHistory,然后render Reouter替換原來(lái)的App組件。這是由于:React Router 是一個(gè)組件。Router 本身是一個(gè)容器,真正的路由都要由Route去定義。
// ...

import { Router, Route, hashHistory } from 'react-router'

render(( <Router history={hashHistory}>

<Route path="/" component={App}/>

</Router>), document.getElementById('app'))

上面訪問(wèn)的路由為“/”,組件是App。路由的切換由URL得hash變化決定,即URL的#部分發(fā)生變化。
2、添加Scene
.modules/About.js
.modules/Repos.js
// modules/About.js

import React from 'react'export

default React.createClass({ render() { return <div>About</div> }})

// modules/Repos.js

import React from 'react'export

default React.createClass({ render() { return <div>Repos</div> }})

把場(chǎng)景添加到路由里面
// insert into index.js

import About from './modules/About'

import Repos from './modules/Repos'

render(( <Router history={hashHistory}>

<Route path="/" component={App}/>

{/* add the routes here */}

<Route path="/repos" component={Repos}/>

<Route path="/about" component={About}/>

</Router>), document.getElementById('app'))

現(xiàn)在訪問(wèn): http://localhost:8080/#/abouthttp://localhost:8080/#/repos

Lesson3 Navigating with Link
Link類(lèi)似于之前用過(guò)的<a/>標(biāo)簽
// modules/App.js

import React from 'react'import { Link } from 'react-router'

export default React.createClass({

render() {

return ( <div>

<h1>React Router Tutorial</h1>

<ul role="nav">

<li><Link to="/about">About</Link></li>

<li><Link to="/repos">Repos</Link></li>

</ul>

</div> ) }})

訪問(wèn):http://localhost:8080

lesson4 嵌套的路由
這個(gè)功能可以做出類(lèi)似Nav的功能,Route里面可以嵌套多個(gè)Route
// index.js// ...

render((

<Router history={hashHistory}>

<Route path="/" component={App}>

{/* make them children of App */}

<Route path="/repos" component={Repos}/>

<Route path="/about" component={About}/>

</Route>

</Router>), document.getElementById('app'))

在App里面
// modules/App.js// ...

render() {

return (

<div>

<h1>React Router Tutorial</h1>

<ul role="nav">

<li><Link to="/about">About</Link></li>

<li><Link to="/repos">Repos</Link></li>

</ul>

{/* add this */}

{this.props.children}

</div>

) }

則UI結(jié)構(gòu)如下:
<App>
<About/>
</App>
<App>
<Repos/>
</App>

Lesson 5 Active Links
通過(guò)行內(nèi)樣式表改變Link的樣式:
// modules/App.js

<li><Link to="/about" activeStyle={{ color: 'red' }}>About</Link></li>

<li><Link to="/repos" activeStyle={{ color: 'red' }}>Repos</Link></li>

也可以添加className在css文件中設(shè)置樣式
// modules/App.js

<li><Link to="/about" activeClassName="active">About</Link></li>

<li><Link to="/repos" activeClassName="active">Repos</Link></li>

創(chuàng)建css文件,并在index.html中引入
// index.html
<link rel="stylesheet" href="index.css" />
我們不用為每個(gè)Link都添加activeClassName,這里我們使用一個(gè)spread operator
創(chuàng)建modules/NavLink.js
// modules/NavLink.js

import React from 'react'

import { Link } from 'react-router'

export default React.createClass({

render() {

return <Link {...this.props} activeClassName="active"/>

}

})

在modules/App.js中這樣寫(xiě):
// modules/App.js

import NavLink from './NavLink'

<li><NavLink to="/about">About</NavLink></li>

<li><NavLink to="/repos">Repos</NavLink></li>

Lesson 6 URL Params
1、添加一個(gè)帶參數(shù)的路由
建立一個(gè)文件:modules/Repo.js
// modules/Repo.js

import React from 'react'

export default React.createClass({

render() {

return (

<div> <h2>{this.props.params.repoName}</h2> </div>

)

}})

2、在index.js里面添加新路由
// import Repo

import Repo from './modules/Repo'

render((

<Router history={hashHistory}>

<Route path="/" component={App}>

<Route path="/repos" component={Repos}/>

{/* add the new route */}

<Route path="/repos/:userName/:repoName" component={Repo}/>

<Route path="/about" component={About}/>

</Route>

</Router>), document.getElementById('app'))

3、在Repo.js里面添加跳轉(zhuǎn)的Link
// Repos.js

import { Link } from 'react-router'

export default React.createClass({

render() {

return (

<div>

<h2>Repos</h2>

{/* add some links */}

<ul>

<li><Link to="/repos/reactjs/react-router">React Router</Link></li>

<li><Link to="/repos/facebook/react">React</Link></li>

</ul>

</div> )

}})

附:path屬性可以匹配通配符
<Route path="/hello/:name">
:paramName 匹配URL的一個(gè)部分,知道遇到下一個(gè)/、?、#為止。路徑參數(shù)可以通過(guò)this.props.params.paramName獲取
// 匹配 /hello/michael
// 匹配 /hello/ryan
<Route path="/hello(/:name)">
()表示URL的這個(gè)部分是可選的
// /hello
// /hello/micale
// /hello/ryan
<Route path="/files/.">
匹配任意字符直到下一個(gè)字符為止,非貪婪模式
// /files/hello.jpg
// /files/hello.html
<Route path="/files/
">
// /files/
// /files/a
// /files/a/b
<Route path="/*/.jpg">
**匹配任意字符,直到遇到下一個(gè)/、?、#為止,貪婪模式
// /files/hello.jpg
// /files/path/to/file.jpg

路由匹配規(guī)則是從上到下執(zhí)行,一旦發(fā)現(xiàn)匹配,就不再匹配其余的規(guī)則了。

Lesson 7 更多的嵌套
1、將Repo的路由放進(jìn)Repos的路由
//index.js

<Route path="/repos" component={Repos}>

<Route path="/repos/:userName/:repoName" component={Repo}/>

</Route>

//Repos.js

<div>

<h2>Repos</h2>

<ul>

<li><Link to="/repos/reactjs/react-router">React Router</Link></li>

<li><Link to="/repos/facebook/react">React</Link></li>

</ul>

{/* will render Repo.js when at /repos/:userName/:repoName */} #{this.props.children}

</div>

2、添加NavLink
// modules/Repos.js
import NavLink from './NavLink'

<li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li>

<li><NavLink to="/repos/facebook/react">React</NavLink></li>

Lesson 8 Index Routes
當(dāng)我們?cè)L問(wèn)/在app里出現(xiàn)了一個(gè)空白,我們想讓他渲染一個(gè)Home的component
IndexRoute顯示指定Home是根路由的子組件,即指定默認(rèn)情況下加載的子組件。IndexRoute組件沒(méi)有路徑參數(shù)path
//modules/Home.js

import React from 'react'

export default React.createClass({

render() {

return <div>Home</div>

}

})

在App里如果沒(méi)有任何場(chǎng)景被渲染的時(shí)候,就渲染Home
// modules/App.js

import Home from './Home'

<div>

{/* ... */}

{this.props.children || <Home/>}

</div>

添加IndexRoute
// index.js

import { Router, Route, hashHistory, IndexRoute } from 'react-router'

import Home from './modules/Home'

render((

<Router history={hashHistory}>

<Route path="/" component={App}>

{/* add it here, as a child of / */}

<IndexRoute component={Home}/>

<Route path="/repos" component={Repos}>

<Route path="/repos/:userName/:repoName" component={Repo}/>

</Route>

<Route path="/about" component={About}/>

</Route>

</Router>), document.getElementById('app'))

IndexRoute沒(méi)有path ,

Lesson 9 Index Links
添加可以返回Home的方法,IndexLink
//App.js

import { IndexLink } from 'react-router'

<li><IndexLink to="/" activeClassName="active">Home</IndexLink></li>

使用onlyActiveOnIndex Property

<li><Link to="/" activeClassName="active" onlyActiveOnIndex={true}>Home</Link></li>

<li><NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink></li>

Lesson 10 Clean URLs with Browser History
配置瀏覽器歷史
//index.js
// bring in browserHistory instead of hashHistory

import { Router, Route, browserHistory, IndexRoute } from 'react-router'

render((

<Router history={browserHistory}>

{/* ... */}

</Router>

), document.getElementById('app'))

點(diǎn)擊鏈接,然后刷新,會(huì)得到

Cannot GET /repos

這是因?yàn)榉?wù)器端配置的原因,目前的服務(wù)器不知道如何處理URL
在package.json中添加:

"start": "webpack-dev-server --inline --content-base . --history-api-fallback"

同時(shí)要將我們的文件引用,相對(duì)路徑為絕對(duì)路徑
//index.html

<link rel="stylesheet" href="/index.css">

<script src="/bundle.js"></script>

重啟服務(wù)器:npm start

Lesson 11 Production-ish Server
Webpack dev server 不是生產(chǎn)模式的服務(wù)器,下面配置生產(chǎn)模式下的服務(wù)器
安裝依賴模塊:

npm install express if-env compression --save

更新package.json

"scripts": {

"start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",

"start:dev": "webpack-dev-server --inline --content-base . --history-api-fallback",

"start:prod": "webpack && node server.js"

},

此時(shí)的腳本說(shuō)明,如果運(yùn)行npm start 啟動(dòng)服務(wù)器,如果在生產(chǎn)環(huán)境下執(zhí)行start:prod,如果不是,執(zhí)行start:dev
在根目錄下創(chuàng)建server.js
//server.js

var express = require('express')

var path = require('path')

var compression = require('compression')

var app = express()

// serve our static stuff like index.css

app.use(express.static(__dirname))

// send all requests to index.html so browserHistory in React Router works

app.get('*', function (req, res) {

res.sendFile(path.join(__dirname, 'index.html'))

})

var PORT = process.env.PORT || 8080

app.listen(PORT, function() {

console.log('Production Express server running at localhost:' + PORT)

})

現(xiàn)在運(yùn)行:NODE_ENV=production npm start
現(xiàn)在就有了生產(chǎn)環(huán)境下的app
此時(shí)運(yùn)行:http://localhost:8080/package.json就可以獲得json文件的內(nèi)容,讓我們重新更新文件的路徑來(lái)解決這個(gè)問(wèn)題
創(chuàng)建一個(gè)public的文件夾,并且把index.html 和 index.css文件放進(jìn)去
1、更新server.js指向正確的路徑:
// server.js

app.use(express.static(path.join(__dirname, 'public')))

app.get('*', function (req, res) {

res.sendFile(path.join(__dirname, 'public', 'index.html'))

})

2、更新webpack編譯時(shí)的輸出路徑
// webpack.config.js

output: {

path: 'public',

}

3、在服務(wù)器啟動(dòng)腳本中,添加該路徑

"start:dev": "webpack-dev-server --inline --content-base public --history-api-fallback",

4、添加一些代碼
// webpack.config.js

var webpack = require('webpack')

module.exports = {

//...

plugins: process.env.NODE_ENV === 'production' ? [ new #webpack.optimize.DedupePlugin(), new #webpack.optimize.OccurrenceOrderPlugin(), new #webpack.optimize.UglifyJsPlugin() ] : [],

//...

}

在express中添加conpression
// server.js

var compression = require('compression')

var app = express()

// must be first!

app.use(compression())

現(xiàn)在我們可以在生產(chǎn)模式下啟動(dòng)服務(wù)器了
NODE_ENV=production npm start

Lesson 12 Navigating Programatically
之前使用的都是Link進(jìn)行路由的跳轉(zhuǎn),而實(shí)際使用更多的使用表單提交,按鈕點(diǎn)擊來(lái)進(jìn)行路由的切換
在Repos創(chuàng)建一個(gè)表單提交
// modules/Repos.js

Paste_Image.png

那么可以使用以下方式保存路由

Paste_Image.png

Lesson 13 服務(wù)器端渲染
Lesson 14 結(jié)束語(yǔ)

附:組件介紹
1、Redirect組件:<Redirect>用于路由的跳轉(zhuǎn),即訪問(wèn)一個(gè)路由,就會(huì)自動(dòng)跳轉(zhuǎn)到另一個(gè)路由.
<Route path="inbox" component={Inbox}>
{/* 從 /inbox/messages/:id 跳轉(zhuǎn)到 /messages/:id */}
<Redirect from="messages/:id" to="/messages/:id" />
</Route>
訪問(wèn)/inbox/message/5,會(huì)自動(dòng)跳到/messages/5
2、IndexRedirect 組件
訪問(wèn)根路由的時(shí)候,將用戶重定向到某個(gè)子組件。
3、Link 組件取代<a>標(biāo)簽,
4、IndexLink 如果連接到根路由不要使用Link要使用IndexLink(使用路由的精確匹配)
5、history屬性
Router的history屬性監(jiān)聽(tīng)瀏覽器地址的變化,并將URL解析為一個(gè)地址對(duì)象,供React Router 匹配
6、表單處理:Link組件用于正常的用戶點(diǎn)擊跳轉(zhuǎn),但有時(shí)候還需要表單跳轉(zhuǎn)、點(diǎn)擊按鈕跳轉(zhuǎn)。
有兩種方案:1、使用browserHistory.push
2、使用context對(duì)象
7、路由的鉤子
每個(gè)路由都有Enter和Leave的鉤子,當(dāng)用戶進(jìn)入或者離開(kāi)該路由時(shí)觸發(fā)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容