在 react-router-dom 的官方教程中,一共給出12個示例,但是個人認為,著12個示例看著真的很累人,很多寫法,不是標準的企業專案應用的寫法,所以針對這個現狀,我想用企業專案開發的要求,對教程中的每一個示例進行重寫,這篇教程就是它的第一個示例——基本使用和介紹。
HashRouter還是BrowserRouter
react-router 的工作方式,是在元件樹頂層放一個Router元件,然後在元件樹中散落著很多reactr 元件,頂層的Router元件負責分析監聽URL的變化,在它保護傘之下的Route元件可以直接讀取這些資訊。
很明顯,Router和Route的配合,就是之前我們介紹過的"提供者模式",Router是 "提供者" ,Route是 "消費者"。
Router其實也是一層抽象,讓下面的Route無需各種不同URL設計的細節,不要以為 URL就一種設計方法,至少可以分為兩種。
第一種:比如 / 對應 Home 頁, /about對應about 頁,但是這樣的設計需要伺服器端渲染, 應為使用者可以直接訪問任何一個URL,伺服器必須能對 / 的訪問返回HTML, 也要對 /about 的訪問返回HTML。
第二種:只有一個路徑 / ,通過URL後面的 # 部分來決定路由, /#/ 對應Home頁。 /#/about 對應About頁。應為URL種 # 之後的部分是不會傳送給伺服器的,所以, 無論哪個URL,最後都是訪問伺服器的 / 路徑,伺服器也只需要返回同一份HTNL就可以,然後由瀏覽器端解析 # 後的部分 ,完成瀏覽器端渲染。
元件
一個使用了 HTML5 history API 的高階路由元件,保證你的 UI 介面和 URL 保持同步。此元件擁有以下屬性:
- basename: string 為所有位置新增一個基準URL. 使用場景:假如你需要把頁面部署到伺服器的二級目錄,你可以使用 basename 設定到此目錄。
<BrowserRouter basename="/wsm" />
<Link to="/react" /> // 最終渲染為 <a href="/minooo/react">
複製程式碼
- getUserConfirmation: func 導航到此頁面前執行的函式,預設使用 window.confirm 使用場景:當需要使用者進入頁面前執行什麼操作時可用,不過一般用到的不多。
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation('Are you sure?', yourCallBack)} />
複製程式碼
- forceRefresh: bool 作用:當瀏覽器不支援 HTML5 的 history API 時強制重新整理頁面。 使用場景:同上。
const supportsHistory = 'pushState' in window.history
<BrowserRouter forceRefresh={!supportsHistory} />
複製程式碼
- keyLength: number 作用:設定它裡面路由的 location.key 的長度。預設是6。(key的作用:點選同一個連結時,每次該路由下的 location.key都會改變,可以通過 key 的變化來重新整理頁面。) 使用場景:按需設定。
<BrowserRouter keyLength={12} />
複製程式碼
最後展示例項:
<BrowserRouter
basename="/minooo"
forceRefresh={false}
getUserConfirmation={getConfirmation()}
keyLength={12}
></BrowserRouter>
複製程式碼
自帶三個 render method 和三個 props 。 render methods 分別是:
- Route component
- Route render
- Route children
props 分別是:
- match
- location
- history
所有的 render method 無一例外都將被傳入這些 props。
component
只有當訪問地址和路由匹配時,一個 React component 才會被渲染,此時此元件接受 route props (match, location, history)。
當使用component時,router將使用React.createElement根據給定的Component建立 一個新的React元素。這意味著如果你使用行內函數傳值給component將會產生不必要的重複裝載。對於內聯渲染(inline rendering), 建議使用 render prop。
<Route path="/user/:username" component={User} />
const User = ({ match }) => {
return <h1>Hello {match.params.username}!</h1>
}
複製程式碼
to: string
作用:跳轉到指定路徑
使用場景:如果只是單純的跳轉就直接用字串形式的路徑。
to: object 作用:攜帶引數跳轉到指定路徑 作用場景:比如你點選的這個連結將要跳轉的頁面需要展示此連結對應的內容,又比如這是個支付跳轉,需要把商品的價格等資訊傳遞過去。
<Link to={{
pathname: '/course',
search: '?sort=name',
state: { price: 18 }
}} />
複製程式碼
這是 的特殊版,顧名思義這就是為頁面導航準備的。因為導航需要有 “啟用狀態”。
activeClassName: string
導航選中啟用時候應用的樣式名,預設樣式名為 active
<NavLink
to="/about"
activeClassName="selected"
>MyBlog</NavLink>
複製程式碼
只渲染出第一個與當前訪問地址匹配的 或 。
Prompt
當使用者離開當前頁面前做出一些提示。
- message: string 當使用者離開當前頁面時,設定的提示資訊。
- message: func 當使用者離開當前頁面時,設定的回掉函式
<Prompt message={location => (
`Are you sue you want to go to ${location.pathname}?`
)} />
複製程式碼
- when: bool 通過設定一定條件要決定是否啟用 Prompt
<Prompt
when={this.state.dirty}
message="資料尚未儲存,確定離開?" />
複製程式碼
物件和方法
match
match 物件包含了 如何與 URL 匹配的資訊,具有以下屬性:
- params: object 路徑引數,通過解析 URL 中的動態部分獲得鍵值對
- isExact: bool 為 true 時,整個 URL 都需要匹配
- path: string 用來匹配的路徑模式,用於建立巢狀的
- url: string URL 匹配的部分,用於巢狀的 在以下情境中可以獲取 match 物件
- 在Route component 中,以 this.props.match獲取
- 在 Route render 中,以 ({match}) => () 方式獲取
- 在 Route children 中,以 ({match}) => () 方式獲取
- 在 withRouter 中,以 this.props.match的方式獲取
- matchPath 的返回值
location
location 是指你當前的位置,將要去的位置,或是之前所在的位置
在以下情境中可以獲取 location 物件
- 在 Route component 中,以 this.props.location 獲取
- 在 Route render 中,以 ({location}) => () 方式獲取
- 在 Route children 中,以 ({location}) => () 方式獲取
- 在 withRouter 中,以 this.props.location 的方式獲取 location 物件不會發生改變,因此可以在生命週期的回撥函式中使用 location 物件來檢視當前頁面的訪問地址是否發生改變。這種技巧在獲取遠端資料以及使用動畫時非常有用
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
// 已經跳轉了!
}
}
複製程式碼
可以在不同情境中使用 location:
- Link to={location} />
- NaviveLink to={location} />
- Redirect to={location />
- history.push(location)
- history.replace(location)
history
history 物件是可變的,因為建議從 的 prop 裡來獲取 location,而不是從 history.location 直接獲取。這樣可以保證 React 在生命週期中的鉤子函式正常執行,例如以下程式碼:
class Comp extends React.Component {
componentWillReceiveProps(nextProps) {
// locationChanged
const locationChanged = nextProps.location !== this.props.location
// 錯誤方式,locationChanged 永遠為 false,因為history 是可變的
const locationChanged = nextProps.history.location !== this.props.history.location
}
}
複製程式碼
最後實現的一個簡單完整的react-router
import React, { Component } from 'react';
import './App.css';
import {
BrowserRouter as Router,
Link,
Route,
Switch,
} from 'react-router-dom';
import Home from './components/Home/Home'
class App extends Component {
render() {
const About = ( ) => <h1>About</h1>;
const Nested = () => (
<div>
<Link to="/nested/one">One</Link>
<Link to="/nested/two">Two</Link>
<Link replace to="/nested/Three">Three</Link>
<div>選擇一個點選</div>
<Route path="/nested/:minooo?" render={({match}) => <h2>URL: {match.params.minooo || 'minooo'}</h2>} />
</div>
)
return (
<div className="App">
<Router>
<Link to="/">Home</Link>
<Link to={{ pathname: '/about',search:'?sort=name', state:{ price: 18 } }}>About</Link>
<Link to="/contact/12?name=minooo">Contact</Link>
<Link to="/blog">blog</Link>
<Link to="/nested">Nested</Link>
{/* <NavLink to="/about" activeClassName="active">MyBlog</NavLink> */}
<main>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact/:id" render={({ history, location, match }) =>
<h1>
{console.log(history, location, match)}
<span onClick={() => {history.push('/', {name:'mm'})}}>click me</span>
</h1>} />
<Route path="/blog" children={({ match }) => (
<li className={match?'active': ''}>
<Link to="/">User</Link>
</li>
)} />
<Route path="/nested" render={Nested} />
<Route render={() => <h1>Page not found</h1>} />
</Switch>
</main>
</Router>
</div>
);
}
}
export default App;
複製程式碼