react路由
react-router-dom
最近開始學習reactr-router
,但是看了好多文章都有問題,後來才發現是react-router 4
做了很大的改動,遵循 Just Component 的 API 設計理念。reactr-router
被拆分為reactr-router
、reactr-router-dom
、reactr-router-native
三部分。reactr-router
提供核心的API,其餘兩個則提供兩個特定的執行環境(瀏覽器和react-native)所需的元件。因此所有的路由元件匯入都改為了從react-router-dom
匯入。
安裝
注意如果是用create-react-app腳手架的話,注意安裝方式(yarn或者npm),詳情參考另外一篇react腳手架搭建
npm install --save react-router-dom;
npm install --save react-router-redux;
npm install --save react-router-config;
使用
先看一下基本寫法:
一級路由,做正常的路由切換
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'
class App extends Component {
render() {
return (
<Router basename='/route'>
<div>
<Route path="/" exact component={Home}></Route>
<Route path="/mime" component={Mime}></Route>
<Route path="/list" component={List}></Route>
<ul>
<li>
<Link to="/">home</Link>
</li>
<li>
<Link to="/mime">mime</Link>
</li>
<li>
<Link to="/list">list</Link>
</li>
</ul>
</div>
</Router>
);
}
}
二級路由
在一級路由的基礎上再做路由,通過props中的match屬性可以獲取當前的url(),然後再去拼接二級路由的path。
export default class List extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>列表頁</h1>
<ul>
<li>
<Link to={`${this.props.match.url}/details`}>詳情</Link>
</li>
<li>
<Link to={`${this.props.match.url}/edit`}>編輯</Link>
</li>
</ul>
<Route path={`${this.props.match.url}/details`} component={Details} />
<Route path={`${this.props.match.url}/edit`} component={Edit} />
</div>
);
}
}
帶引數
如果路由後面要攜帶引數,可以這樣寫(最後括號中的值表示只能是這兩個值,如果沒有此限制則可以是任何值)
<Route
path={`${this.props.match.url}/:id(20|100)`}
component={Details}
/>
在子元件中通過this.props.match.params.xx
獲取對應的引數
<h1>{this.props.match.params.id}</h1>
<BrowserRouter>和<HashRouter>
他們就是路由的根基,包裹在最外層。之前使用路由的肯定知道(不管是哪個版本,甚至vue的路由),路由的實現有兩種方法,HashRouter
是利用URL的hash部分實現,在url中會經常有個#號,主要是針對舊版瀏覽器。我們一般都使用BrowserRouter
,它是利用H5的history API實現。
還有一種實現是針對非DOM環境的(react-native),利用記憶體實現。
- basename:如果你的檔案在伺服器的二級目錄下,就會用到它。他會在每一個路由路徑前面自動新增一級目錄。如下圖,當我們點選list時,url中會自動新增route目錄。
該元件下只能有一個子元件,所有元件都要包裹在一層裡。
<Route>
Route就是控制不同路徑去對應顯示內容的元件。配合Link使用。
exact:控制嚴格匹配。如果沒有這個屬性,當訪問
list
時,home元件和list元件會同時被渲染。path:訪問的路徑,如果沒有該屬性,那麼將會匹配一切路徑。
component:path路徑對應要顯示的元件。使用最多。如果要獲取match等物件。可以使用
this.props.match
...render:與component一樣,可以直接在後面寫要渲染的內容。可以獲取到mach物件。
<Route path="/home" render={({match}) => <div>Home</div>}/>
- children:和render是一樣的功能,不過它不論是否匹配到都會呼叫。
<Route path="/mime" component={Mime}></Route>
<Route path="/list" children={({match})=> (
<div>
<h3>哈哈</h3>
<List></List>
</div>
)}></Route>
以上程式碼,不管當前匹配的是mime還是list或是其他,都會渲染list。
<Link>和<NavLink>
Link
的api相對較少,上面我們使用的是最簡單的to,直接跳轉到一個地址。就不多說了。
- to:還可以攜帶引數到指定頁面,後面跟一個物件就可以。如下(可以實現頁面間傳參)
<Link to={{
pathname: '/list',
search: '?sort=name',
state: { id: 2 }
}} />
state可以傳遞任何型別的引數,而且類似於post方式,可以不以明文傳輸。在跳轉的頁面中實用this.props.location.state獲取資料。
- replace:基本不用,為true時會替換掉上次訪問的地址,也就是使用瀏覽器的回退按鈕無法返回上一個頁面。
NavLink
很明顯就是為頁面導航準備的,因為導航是要有啟用狀態的。
- activeClassName:啟用時要渲染的樣式名
<NavLink to="/mime" activeClassName='actvived'>mime</NavLink>
- activeStyle:直接把啟用的樣式寫在後面
<NavLink to="/mime" activeStyle={{color: red,fontSize: 20px}}>mime</NavLink>
exact:如果為true,只有當訪問地址嚴格匹配時才會使用啟用樣式。
strict:如果為true,只有擋訪問地址後的斜槓嚴格匹配(有或沒有)才會使用啟用樣式。
isActive:跟一個函式,當導航啟用時要做的事情。
<StaticRouter>
api中介紹說這是一個從來不會改變位置的Router。當使用者沒有實際點選時,因此位置也從未發生變化。這在服務端渲染很有用,因為在後臺上, 我們只會渲染一次,而且不會直接地對使用者的互動操作做出反應。
看下API中的案例:
import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
createServer((req, res) => {
// 這個context包含渲染的結果
const context = {}
const html = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App/>
</StaticRouter>
)
// 如果使用<Redirect>,context.url將包含要重定向到的URL
if (context.url) {
res.writeHead(302, {
Location: context.url
})
res.end()
} else {
res.write(html)
res.end()
}
}).listen(3000)
- basename:所有位置的基本url,正確的格式應該是前面有
/
後面沒有/
。
<StaticRouter basename="/main">
<Link to="/list"/> <!--渲染出來應該是<a href="/main/list">-->
</StaticRouter>
- location:如果是個字串就應該是伺服器上收到的url(req.url)。如果是個物件應該是一個類似
{pathname, search, hash, state}
的位置物件。
<StaticRouter location={{ pathname: '/home' }}>
<App/>
</StaticRouter>
- context:一個普通js物件,在渲染過程中元件可以向物件裡添屬性以儲存有關渲染的資訊。
我們使用它來找出渲染結果,context上下文物件是自己的,我們可以改變它。
//app上有個404元件,把status改成404
const NotFound = () => (
<Route
render={({ staticContext }) => {
if (staticContext) {
staticContext.status = 404;
}
return (
<div>
<h1>你輸入的地址不正確喲!</h1>
</div>
);
}}
/>
);
// 在服務端我們就可以通過判斷,對這個404介面傳送404響應
const context = {};
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
</Provider>
);
if (context.status === 404) {
res.status(404);
}
或者判斷重定向,如果有context.url就說明應用被重定向,這允許我們從伺服器傳送適當的重定向。
if (context.url) {
// can use the `context.status` that
// we added in RedirectWithStatus
redirect(context.status, context.url)
}
<Switch>
用來包裹Route或者Redirect元件,而且不能放其他元素,用來渲染第一個匹配到的路由,不會向下繼續匹配。如果不用Switch包裹的話,訪問/about時下面三個元件都會被渲染。
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
<Redirect>
將匹配到的路徑重定向到一個新的地址。新的地址應該覆蓋掉訪問的地址。
<Route path="/game" component={Game}></Route>
<Redirect from="/home" to="game" push={true}></Redirect>
from:匹配到的訪問的地址
to:重定向到的地址
push:為true時,重定向到的地址會新增到歷史訪問記錄,並且無法回到之前訪問的地址。
<withRouter>
withRouter可以用來包裝任何自定義元件,並將history
、location
、match
三個物件傳入。這樣元件就可以拿到路由資訊。
import {withRouter} from 'react-router-dom';
const Home = withRouter(({history,location,match})=>{
return <h1>{location.pathname}</h1>
})
history
表示瀏覽器歷史記錄的物件,可以對它進行一系列操作,有以下屬性和方法:
length:獲取歷史堆疊中的條目數
action:獲取當前操作(push/pop/replace)
location:獲取當前位置,包括(pathname、search、hash、state、)
push(''):新增一個新的條目到歷史堆疊(一般會用來跳轉到一個新頁面)
replace(''):替換掉當前堆疊上的條目
go(n):通過n個條目移動歷史堆疊中的指標,向前或向後n個
goBack():後退一個歷史條目,相當於go(-1)。
goForward():前進一個歷史條目,相當於go(1)
block:防止導航
match
<Route path>
如何與url匹配的資訊,包含以下內容:
params:URL動態段解析對應的鍵值對
isExact:如果匹配整個URL則為true
path:<Route>匹配的路徑
url:當前真正訪問的路徑
location
程式當前所在的位置。。。
react-router-redux
如果使用的react-router-redux
(把react-router url的變化、引數等資訊作為狀態,交給redux的store管理),則可以直接從state中獲取路由資訊。
import {routeMiddleware} from 'react-router-redux';
const store = createStore(combineReducers, applyMiddleware(routeMiddleware));
const mapStateToProps = (router) => ({
pathname: rourter.location.pathname
})
export default connect(mapStateToProps)(MyControl)
react-router-config
react-router-config
是幫助我們配置靜態路由的。算是比較好理解的,API只有兩個方法:
matchRoutes(routes, pathname)
該方法接收兩個引數(routes配置,請求路徑),返回一個陣列。
import { matchRoutes } from 'react-router-config'
const branch = matchRoutes(routes, '/child/23')
這個返回的陣列的每一個元素包含兩個屬性routes和match。結構如下:
[
{
route: {
path: '/app',
component: [(Function: component)],
routes: [Array]
},
match: { path: '/app', url: '/app', isExact: false, params: {} }
},
{
route: { path: '/app/resources', component: [Object] },
match: {
path: '/app/resources',
url: '/app/resources',
isExact: true,
params: {}
}
}
];
這個方法在服務端貌似用的多一些,自己沒有用過不說太多。。。
renderRoutes(routes, extraProps = {})
該方法接受兩個引數:配置的路由和要傳的值。
寫這篇文章的時候,react-router-config的renderRoutes方法並沒有更新的npm上,其實已經實現了,不知道為什麼沒有上npm。看下原始碼:
import React from 'react';
import Switch from 'react-router/Switch';
import Route from 'react-router/Route';
const renderRoutes = (routes, extraProps = {}, switchProps = {}) =>
(routes ? (
<Switch {...switchProps}>
{routes.map((route, i) => (
<Route
exact={route.exact}
key={route.key || i}
path={route.path}
render={props =>
(route.render ? (
route.render(props)
) : (
<route.component {...props} {...extraProps} route={route} />
))
}
strict={route.strict}
/>
))}
</Switch>
) : null);
實際上就是在一個<Switch>中建立了多個<Route>
看一下API中給出的程式碼示例,路由可以進行統一的配置了,不過有個缺陷就是:在元件的render方法中還需要呼叫renderRoutes方法。
import { renderRoutes } from 'react-router-config'
// 配置路由
const routes = [
{ component: Root,
routes: [
{ path: '/',
exact: true,
component: Home
},
{ path: '/child/:id',
component: Child,
routes: [
{ path: '/child/:id/grand-child',
component: GrandChild
}
]
}
]
}
]
// 設定路由
ReactDOM.render((
<BrowserRouter>
{renderRoutes(routes)}
</BrowserRouter>
), document.getElementById('root'))
// 在元件中呼叫方法
const Root = ({ route }) => (
<div>
<h1>Root</h1>
{renderRoutes(route.routes)}
</div>
)
const Home = ({ route }) => (
<div>
<h2>Home</h2>
</div>
)
const Child = ({ route }) => (
<div>
<h2>Child</h2>
{renderRoutes(route.routes, { someProp: 'these extra props are optional' })}
</div>
)
const GrandChild = ({ someProp }) => (
<div>
<h3>Grand Child</h3>
<div>{someProp}</div>
</div>
)
相關文章
- react 路由React路由
- React — 路由React路由
- react之路由React路由
- React路由(基礎)React路由
- React初識整理(四)–React Router(路由)React路由
- React路由 基礎:react-router-domReact路由
- react router路由傳參React路由
- React 快速上手 – 07 前端路由 react-routerReact前端路由
- React 快速上手 - 07 前端路由 react-routerReact前端路由
- React 路由的使用方法React路由
- React 小案例 路由跳轉React路由
- react自動處理路由React路由
- [譯] React 路由和 React 元件的愛恨情仇React路由元件
- 七天接手react專案 系列 —— react 路由React路由
- react 路由的幾種使用方式React路由
- React 路由狀態管理總結React路由
- react使用react-router-config 進行路由配置React路由
- react-navigation路由篇之StackRouterReactNavigation路由
- react-native 路由與選單demoReact路由
- 使用react-router-config配置路由React路由
- 手寫那些年用過的React路由React路由
- 深入理解 react-router 路由系統React路由
- 從 React Router 談談路由的那些事React路由
- react中路由傳參和url傳參React路由
- react後臺管理系統路由方案及react-router原理解析React路由
- react-router v4 路由規則解析React路由
- 基於react的hash路由簡易實現React路由
- React-navigation 路由任意跳轉總結ReactNavigation路由
- React乾貨(二):提取公共程式碼、建立路由Store、Check路由引數型別React路由型別
- 前端技術 | react-router,去中心化式路由前端React中心化路由
- react路由引數改變不重新渲染頁面React路由
- React研習之旅(二):檢視控制器-路由React路由
- React服務端渲染(前後端路由同構)React服務端後端路由
- 前端路由實現與 react-router 原始碼分析前端路由React原始碼
- React Router、And、Redux動態選單和動態路由ReactRedux路由
- web前端技術分享:使用react實現簡易路由Web前端React路由
- react全家桶實現招聘app-路由實現(二)ReactAPP路由
- React Router 4 簡介及其背後的路由哲學React路由