簡介: React Router是一個基於 React 之上的強大路由庫,它可讓你嚮應用中快速地添加視圖和數據流,同時保持頁面與URL間的同步。html
router共包含如下幾種:
react-router: React Router 核心
react-router-dom: 用於 DOM 綁定的 React Router
react-router-native: 用於React Native 的 React Router
react-router-redux: React Router 和 Redux的集成
react-router-config: 靜態路由配置的小助手
說明:
今天咱們主要說的是 react-router-dom
react-router-dom包含 HisitoryRouter BrowserRouter等
注意:使用react-router-dom時,只須要引入react-router-dom就能夠了,不須要引入react-router
<BrowserRouter>
使用
import { BrowserRouter, NavLink, Switch, Redirect} from 'react-router-dom'
<BrowserRouter basename={`${path}`}>
<ul id="menu">
<NavLink activeClassName={styles.active} exact to={`/`} />
<NavLink activeClassName={styles.active} to={`/user`} />
</ul>
<div id='page-container' className={styles.container}>
<Switch>
<Route path={`/`} exact component={main} />
<Route path={`/user`} render={(props) => <User pageId="user" />} />
<Redirect to="/" />
</Switch>
</div>
</BrowserRouter>
// NavLink添加activeClassName屬性以後可讓首頁tab默認選中
複製代碼
<Switch>
<Route exact path="/app/" render={() =>
<Redirect to='/app/error'></Redirect>}></Route>
<Route path="/app/users" component={Users}></Route>
<Route path="/app/report" component={Report}></Route>
<Route path="/app/error" component={ErrorPage}></Route>
<Redirect to="/app/" />
</Switch>
說明:
一、地址欄輸入 /app/user ,跳轉到指定的Users組件
二、exact指定輸入 /app/重定向redirect to /app/error,重定向到ErrorPage組件中
3. 若是輸入錯誤的地址,重定向到/app/路由,跳轉到ErrorPage組件中
注意:重定向分兩種 1.指定重定向,2.模糊重定向
複製代碼
<Switch>
只渲染出第一個與當前地址匹配的<Route>
或<Redirect>
node
Switch解決的問題:若是你訪問/about
,那麼與/about
相關的路徑都將被渲染出來,如/about/user
,由於他們對應的路由與訪問的地址/about
匹配。這顯然不是咱們想要的,咱們只想渲染出第一個匹配的路由就能夠了,因而<Switch>
應用而生!react
Historyredux
pushState()瀏覽器
popstate性能優化
路由實現 - history
<header>
<a onclick="changeRoute(this)" data-path="home">首頁</a>
<a onclick="changeRoute(this)" data-path="center">我的中心</a>
<a onclick="changeRoute(this)" data-path="help">幫助</a>
</header>
<section id="content"></section>
<script>
/**
Hisotory.pushState(state, title, url) 按指定的名稱和URL(若是提供該參數)將數據push進回話歷史棧。
state: 一個與添加的記錄相關聯的狀態對象,主要用於popstate事件,該事件觸發時,該對象會傳入回調函數。也就是說,瀏覽器會將這個對象序列化之後保留在本地,從新載入這個頁面的時候,能夠拿到這個對象。若是不須要這個對象,此處能夠填爲null
title: 新頁面的標題。可是,如今全部瀏覽器都忽視這個參數,因此這裏能夠填空字符串。
url: 新的網址,必須與當前頁面處在同一個域。瀏覽器的地址欄將顯示這個地址。
*/
function changeRoute (route) {
let path = route.dataset.path
changePage(path)
history.pushState({content: path}, null, path)
}
/**
當活動歷史記錄條目更改時,將觸發popstate事件。history.pushState()的調用建立的,或者受到對 history.replaceState()的調用的影響,popstate事件的state屬性包含歷史條目的狀態對象的副本。
history.pushState() 或者 history.replaceState()不會觸發popstate事件。只有在作出瀏覽器動做時,纔會觸發該事件,如用戶點擊瀏覽器的回退按鈕 或者在js代碼中調用history.back()
*/
window.addEventListener('popstate', (e) => {
let content = e.state && e.state.content
changePage(content)
})
function changePage (pageContent) {
let content = document.getElementById('content')
content.innerText = pageContent
}
</script>
複製代碼
BrowerRouterbash
<BrowerRouter>
使用HTML5的history
API (pushState
、replacestate
popstate
事件)來同步URL和UI服務器
<BrowerRouter basename={optionalString} forceRefresh={optionlBool} getUserConfirmation={optionlFunc} keyLength={optionlNumber}>
<App/>
</BrowerRouter>
複製代碼
屬性介紹babel
basename: string
:基準URL.適用於當應用置於服務器上子目錄的狀況下。數據結構
forceRefresh: bool
: 當設爲true
時,每次跳轉都會刷新頁面。通常只在瀏覽器不支持HTML history API
的狀況下使用。
getUserConfirmation: func
: 能夠傳入一個函數,用來肯定導航前的用戶確認行爲,默認使用window.confirm
,以下:
keyLength: number
: 設置location.key
的長度,默認爲6位
children: node
:子元素裏只能渲染單一的元素
HashRouter
使用URL中的hash部分(即window.location.hash
)來保持UI和URL同步
注意:HashHistory不支持location.key
或location.state
,因此任何須要這兩個屬性的代碼或者插件將不能起做用。因爲HashHisitory
這種技術的主要目的是支持老式瀏覽器,因此官方更推薦的作法是對服務器進行配置,而後採用<BrowerRouter>
代替。
MemoryRouter
在內存中記錄history的路由組件(這種路由不會讀取或者寫入地址欄),適合用於測試或者非瀏覽器環境(如ReactNative
)
導航跳轉
爲應用提供聲明式、可訪問的導航的一個組件:
import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
複製代碼
參數: to: string 要跳轉到的 pathname 或者 location
to: object
用法:
<Link to={{
pathname: '/course',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}} />
複製代碼
replace: bool 當這個值爲 true 時,會替換掉history棧裏當前的history,而不是在棧裏新增一條history,如:
<Link to="/courses" replace>
複製代碼
<Link>
組件的特殊版本,當前URL匹配時,會在元素上增長樣式相關的屬性activeClassName
,從而達到高亮標記的效果。
import { NavLink } from 'react-router-dom'
<NavLink to="/about">About</NavLink>
複製代碼
參數:
activeClassName: string
規定處於激活狀態時的類名,默認值是active
,會自動和className屬性合併:
<NavLink to="/faq" activeClassName="selected">FAQs</NavLink>
複製代碼
activeStyle: object
規定激活狀態下應用到元素上的樣式:
<NavLink to="/faq" activeStyle={{
fontWeight: 'bold',
color: 'red'
}}>FAQs</NavLink>
複製代碼
exact: bool
設爲true
時,只有當location徹底匹配的時候纔會添加類名或者樣式: 與Switch的區別
<NavLink exact to="/profile">Profile</NavLink>
複製代碼
strict: bool
:當設爲 true
時,location中pathname
末尾的/
就會在匹配URL的時候被考慮: 就是說有/
和沒有/
的結果徹底不一樣
<NavLink strict to="/events/">Events</NavLink>
複製代碼
isActive: func
:用來爲link添加判斷激活狀態額外邏輯的函數,如:
isActive能夠經過邏輯來控制
// 只有當事件ID爲奇數時纔可能爲激活狀態
const oddEvent = (match, location) => {
if (!match) {
return false
}
const eventID = parseInt(match.params.eventID)
return !isNaN(eventID) && eventID % 2 === 1
}
<NavLink to="/events/263" isActive={oddEvent}>Event 263</NavLink>
複製代碼
location: object
isActive
函數裏用來比較用的值(即傳入的第二個參數),一般狀況下取值爲當前瀏覽器的URL.若是要和不一樣的location比較,就能夠用這個屬性來傳值。
<NavLink activeClassName={styles.active} exact to={`/`} />
複製代碼
二. Router、Route與Switch 一、Router 通用的基礎路由組件。一般在應用裏會採用派生的路由代替,有:
<BrowserRouter>
<HashRouter>
<MemoryRouter>
<NativeRouter>
<StaticRouter>
最經常使用的直接採用<Router>
的場景是用狀態管理庫(Redux、Mobx)來同步一個自定義的history。不過應當注意的是:這不是說必須結合狀態管理庫使用ReactRouter,只是在深度集成的時候須要用到:
import { Router } from 'react-router'
import createBrowserHistory from 'history/createBrowserHistory'
const history = createBrowserHistory()
<Router history={history}>
<App />
</Router>
複製代碼
參數:
history: object 用來導航用的history對象
二、Route
組件也許是ReactRouter裏最須要好好理解和使用的最重要的一個組件。它的基本職責是在location匹配路由的path參數值時渲染特定的UI:
import { BrowserRouter as Router, Route } from 'react-router-dom'
<Router>
<div>
<Route exact path="/" component={Home} />
<Route path="/news" component={NewsFeed} />
</div>
</Router>
複製代碼
當location是/時,UI將會渲染爲:
<div>
<Home />
<!-- react-empty: 2 -->
</div>
複製代碼
而若是當UI是/news時,UI將會渲染爲:
<div>
<!-- react-empty: 1 -->
<NewsFeed />
</div>
複製代碼
react-empty
註釋,只是React的null渲染的實現。可是這種作法是有益的,從技術上而言一個Route應該老是被渲染出來即便結果是渲染null,而只要應用的location和Route的path匹配,那麼對應的組件就會獲得渲染。
2-一、路由渲染方法
渲染一個路由有三種方式:
<Route component>
<Route render>
<Route children>
每一種方式在不一樣的情景下都是有用的,可是在<Route>
裏只能同時用一個屬性,不過大部分狀況下用的是component
注意: 因爲優先級上:component > render > children
,因此在<Route>
裏最多隻能選用一種。
首先須要知道的是,這三種方式都會獲得match、location、history
這三個路由屬性。
說明:
component
方式,代表location匹配時要渲染的React組件,組件可使用路由屬性來進行渲染:
<Route path="/user/:username" component={User} />
const User = ({ match }) => {
return <h1>Hello, {match.params.username}!</h1>
}
複製代碼
當使用這種方式時,路由系統會使用React.createElement
來從給定的組件裏建立一個新的React
元素。這意味着若是傳給component
屬性的是一個內聯的函數,那麼每次渲染時就都會 建立一個新的組件。這就會致使現有的組件卸載,而後掛載新的組件。而非更新已有的組件。因此要使用內聯函數來進行內聯渲染時,可使用render方式或者children方式
render: func
方式,這種方式將方便於內聯渲染,而且不會有上述的從新掛載問題。咱們能夠傳入一個函數,那麼當location匹配的時候這個函數就會被調用,從而不會進行新的React元素建立過程。render屬性接收和component屬性一致的路由屬性:
<Route path="/home" render={() => <div>Home</div>} />
const FadingRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props} />
</FadeIn>
)} />
)
<FadingRoute path="/cool" component={Something} />
複製代碼
children: func
方式,有時候,不管path
是否成功匹配都須要進行渲染。那麼這種狀況下,可使用children
屬性方式,這種方式不管匹配是否成功都會調用對應的函數。 而children
渲染屬性接收和component、render
方式同樣的屬性,不過當路由不匹配的時候,match
的值是null
。因此採用這種方式的好處是,咱們能夠靈活地動態調整UI,不管路由是否匹配。舉例如:
路由匹配時添加激活狀態的類名:
<ul>
<ListItemLink to="/somewhere" />
<ListItemLink to="/somewhere-else" />
</ul>
const ListItemLink = ({to, ...rest}) => (
<Route path={to} children={({ match }) => (
<li className={match ? 'active' : ''}>
<Link to={to} {...rest} />
</li>
)}/>
)
複製代碼
對於動畫而言,這種方式也是有用的:
<Route children={({ match, ...rest }) => (
// 由於動畫會一直渲染,因此可使用生命週期來讓子元素動畫進出
<Animate>
{match && <Something {...rest}/>}
</Animate>
)}
複製代碼
三、Switch
渲染子元素裏第一個匹配的<Route>
或者<Redirect>
,那麼,和只使用一堆<Route>
不一樣的是什麼? <Switch>
獨一無二的是它只渲染一個路由。而反過來,每一個匹配location的<Route>
都會被獲得渲染,參考以下代碼:
<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={NoMatch} />
複製代碼
若是URL是/about,那麼<About>
、<User>
和<NoMatch>
都會渲染,由於它們的path都獲得了匹配。而這種設計是有意的,由於這使得咱們能夠用多種方式來用<Route>
組成咱們的應用,如側邊欄、麪包屑、引導Tab等。
不過有時候,咱們只想要拾取一個<Route>
來渲染,就好比URL處於/about
時就不但願它匹配/:user
(或者展現404頁面),如:
import { Switch, Route } from 'react-router'
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={NoMatch} />
</Switch>
複製代碼
如今,若是URL是/about
,那麼<Switch>
就會開始尋找匹配的<Route>
。<Route path="/about"/>
將會匹配,從而<Switch>
就會中止匹配而後渲染出<About>
組件。類似地,若是URL處於/michael
,那麼<User>
組件就會渲染。
對於動畫過渡而言,這也是一種有用的方式,由於匹配的<Route>
須要渲染在先前相同的位置:
<Fade>
<Switch>
{/* 這裏只會有一個子節點 */}
<Route/>
<Route/>
</Switch>
</Fade>
<Fade>
<Route/>
<Route/>
{/*
這裏一直都會有兩個子節點,儘管其中一個可能爲null,
這會使得過渡效果起效果有點難處理
*/}
</Fade>
複製代碼
參數說明:
location: object
和以前其餘地方里含義一致 children: node
<Switch>
組件的子元素都應該是<Router>
或者<Redirect>
,而且只有匹配當前URL的第一個子元素會被渲染。其中,<Route>
元素使用path
屬性來進行匹配,而<Redirect>
使用from
屬性進行匹配。而不帶path屬性的<Route>
元素或者不帶from屬性的<Redirect>
元素會老是匹配當前location
因此當在<Switch>
裏使用<Redirect>
組件時,它可使用和<Route>
同樣的匹配屬性:path、exact、strict
,而from只是path屬性的別名。
當給<Switch>
傳入location
屬性時,會覆蓋當前匹配的子元素中的location
<Switch>
<Route exact path="/" component={Home} />
<Route path="/users" component={Users} />
<Redirect from="/accounts" to="/users" />
<Route component={NoMatch} />
</Switch>
複製代碼
異步獲取數據
複製代碼
複製代碼
在接口的設計上應體現出數據與業務的相分離。下降耦合性。在代碼的設計上也要儘可能下降重複性代碼。在寫代碼以前要清楚接口的數據結構,設計好代碼結構,儘可能減小在寫代碼時候頻繁修改代碼。
複製代碼
7.API
react中最重要的三個API: createElement 、render、 component
component(react中一切皆組件)中包含setState
virtual Dom
jsx表面看是HTML標籤,其實是下面這套內容
React.createElement(
"div",
null,
"hello ",
this.props.name,
" ,I am",
{2 + 2},
"years old"
)
複製代碼
是jsx的babel作的編譯,jsx表面是html,其實是js
React.createElement
返回的數據
JSX
本質上就是轉換爲React.createElement
在react內部構建虛擬dom,最終渲染出頁面
React.createElement
是用來建立虛擬DOM的
React.createElement
是一個遞歸調用的過程,也就是說dom中嵌套dom,會嵌套相應個數的React.createElement
學習一個庫的最好方法,先開發一個小應用,而後嘗試理解源碼。
參考連接:ReactRouter4學習筆記
<div>
<A />
<B>
<C />
<D />
</B>
</div>
複製代碼
請說出componentWillUpdate
和componentDidUpdate
中A B C D
四個組件的執行順序。
A B C D
複製代碼
A C D B
複製代碼
原理:當組件更新時,若是組件的props和state都沒發生改變,render方法都不會觸發,省去Virtual DOM的生成和對比過程,達到提高性能的目的。React自動幫咱們作了一層淺比較。 PureComponent真正起做用的,只是在一些純展現組件上,複雜組件使用的話shallowEqual那一關基本就過不了。
shouldComponentUpdate
不可變數據的力量,返回新對象,而不是修改老對象。
大部分狀況下,可使用 React.PureComponent 來代替手寫 shouldComponentUpdate。
setState
只在合成事件和鉤子函數中是"異步"的,在原生事件和setTimeout
中都是同步的。setState
的"異步"並非說內部由異步代碼實現,其實自己執行的過程和代碼都是同步的,只是合成事件和鉤子函數的調用順序在更新以前,致使在合成事件和鉤子函數中無法立馬拿到更新後的值,造成了所謂的「異步」,也能夠經過第二個參數 setState(partialState, callback) 中的callback拿到更新後的結果。setState
的批量更新優化也是創建在「異步」(合成事件、鉤子函數)之上的,在原生事件和setTimeout
中不會批量更新,在「異步」中若是對一個值進行屢次setState
,setState
的批量更新策略會對其進行覆蓋,取最後一次的執行,若是是同時setState
多個不一樣的值,在更新時會對其進行合併批量更新。redux-thunk爲何能讓action發送函數 redux-thunk是對dispatch方法作一個升級,以前這個dispatch方法只能接收一個對象,升級以後,就能夠接收函數了。根據參數的不一樣執行不一樣的事情,若是是對象就直接傳遞給store,若是是函數就先執行函數,在調用dispatch。原理就是對store的dispatch方法作了一個升級。
4、Props.childern