博主翻譯原教程目的(加了一些博主自己解讀),一是博主自己進(jìn)一步了解React Router 4,二是官網(wǎng)的教程確實(shí)還需加強(qiáng)引導(dǎo)性和增加案例多樣性。從React Router 4 的心智模型。看后面對(duì)這個(gè)詞的解釋,就明白了有些伙伴們對(duì)4的質(zhì)疑。
目的
此指南的目的為了說明使用 React Router 4 時(shí)的心智模型。我們稱之為的”動(dòng)態(tài)路由“,這與你熟悉的”靜態(tài)路由“有很大的不同。
注釋:心智模型是經(jīng)由經(jīng)驗(yàn)及學(xué)習(xí),腦海中對(duì)某些事物發(fā)展的過程,所寫下的劇本,是個(gè)體為了要了解和解釋他們的經(jīng)驗(yàn),所建構(gòu)的知識(shí)結(jié)構(gòu),該模型受限于個(gè)體關(guān)于他們經(jīng)驗(yàn)的內(nèi)隱理論,這可能有很多或很少的正確性。
靜態(tài)路由
如果你使用 Rails, Express, Ember, Angular 等。你已經(jīng)使用了靜態(tài)路由。在這些框架中,在任何渲染發(fā)生之前,將申明路由作為應(yīng)用程序初始化一部分。
React Router 4 之前的版本也是靜態(tài)的(主要是)。讓我們看看在 Express 里如何配置路由:
const express = require('express');
const app = express();
app.get('/', handleIndex)
app.get('/invoices', handleInvoices)
app.get('/invoices/:id', handleInvoice)
app.get('/invoices/:id/edit', handleInvoiceEdit)
app.listen()
注意:在應(yīng)用程序監(jiān)聽之前如何讓路由被申明。這和我們使用的客戶端路由是相似的。在 Angular 中,首先申明路由并且在渲染之間把他們導(dǎo)入到頂級(jí)的 AppMoudule :
const appRoutes: Routes = [
{ path: 'crisis-center',
component: CrisisListComponent
},
{ path: 'hero/:id',
component: HeroDetailComponent
},
{ path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
{ path: '',
redirectTo: '/heroes',
pathMatch: 'full'
},
{ path: '**',
component: PageNotFoundComponent
}
];
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
]
})
export class AppModule { }
Ember有一個(gè)常規(guī)的 routes.js 文件,它可以構(gòu)建讀取并導(dǎo)入到應(yīng)用程序里。同樣,在應(yīng)用渲染之前發(fā)生。
Router.map(function() {
this.route('about');
this.route('contact');
this.route('rentals', function() {
this.route('show', { path: '/:rental_id' });
});
});
export default Router
雖然 API 是不同的,他們共享”靜態(tài)路由“模式。React Router 4之前也是這樣的模式。
如果要使用React Router,那么你需要忘記這一切!
背景故事
坦白的說,我們非常郁悶,因?yàn)榈诙娌捎昧?React Router。我們感到被API 限制了。認(rèn)識(shí)到我們正在重新實(shí)現(xiàn) React 的一部份(生命周期等),并且它不能符合 React 給我們編寫的用戶界面的心智模型。
一次研究討論會(huì)前,我們正走走過一家酒店的長(zhǎng)走廊。我們相互討論:”如果我們使用在研討論會(huì)中的模式構(gòu)建路由器會(huì)是什么樣?“
動(dòng)態(tài)路由
靜態(tài)路由:任何渲染發(fā)生之前,將申明路由作為應(yīng)用程序初始化一部分。
當(dāng)我們說動(dòng)態(tài)路由,在應(yīng)用程序正在渲染時(shí)發(fā)生的路由,不是運(yùn)行應(yīng)用程序之外的配置或約定中。在React Router 中一切都是一個(gè)組件。下面是一個(gè) API 回顧,看下它如何工作的。
首先,在應(yīng)用頂部
// react-native
import { NativeRouter } from 'react-router-native'
// react-dom
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render((
<BrowserRouter>
<App/>
</BrowserRouter>
), el)
其次,用 Link 組件去鏈接一個(gè)新定位:
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
</div>
)
最后,當(dāng)用戶訪問 /dashboard 時(shí),會(huì)去渲染一個(gè)路由去顯示用戶界面。
const App = () => (
<div>
<nav>
<Link to="/dashboard">Dashboard</Link>
</nav>
<div>
<Route path="/dashboard" component={Dashboard}/>
</div>
</div>
)
路由將渲染 <Dashboard {...props}/>,props 是一些路由器特定的東西,看起來像 {match, location, history} 。如果 /dashboard 鏈接不存在,那么路由將呈現(xiàn)為空。這幾乎就是全部了。
嵌套路由
什么情況下用到嵌套路由,比如應(yīng)用左側(cè)邊欄是個(gè)菜單,點(diǎn)擊不同內(nèi)容時(shí),右側(cè)界面對(duì)應(yīng)相應(yīng)一個(gè)路由并且隨著變化。
許多路由有一些概念性的 ”嵌套路由"。如果你已經(jīng)使用過 React Router 4 之前的版本,那么也將知道它是什么。當(dāng)你從一個(gè)靜態(tài)路由配置移到動(dòng)態(tài)的渲染路由,知道怎么做嗎?怎么嵌套一個(gè)div?
const App = () => (
<BrowserRouter>
{/* 這里有個(gè)div */}
<div>
{/* 路由 */}
<Route path="/tacos" component={Tacos}/>
</div>
</BrowserRouter>
)
// when the url matches `/tacos` this component renders
const Tacos = ({ match }) => (
// 有一個(gè)嵌套div
<div>
{/* 有一個(gè)嵌套路由,match.url 幫助我們做一個(gè)相對(duì)路徑 */}
<Route
path={match.url + '/carnitas'}
component={Carnitas} />
</div>
)
可以看出,這里并沒有嵌套 API ,路由只是一個(gè)組件而已,就像 div 一樣。所以嵌套一個(gè)路由或 div , 照著這樣做就行了。
響應(yīng)式路由
用戶先導(dǎo)航到 /invoices。應(yīng)用能自適應(yīng)不同尺寸的屏幕,它們有一個(gè)小的適配器,而且能展示它們 invoices 列表和鏈接到 invoice/dashboard。它們可以深度導(dǎo)航。
小屏幕
路由地址: /invoices
+----------------------+
| |
| Dashboard |
| |
+----------------------+
| |
| Invoice 01 |
| |
+----------------------+
| |
| Invoice 02 |
| |
+----------------------+
| |
| Invoice 03 |
| |
+----------------------+
| |
| Invoice 04 |
| |
+----------------------+
在一個(gè)大屏幕上,我們想點(diǎn)擊左邊的 Dashboard 就在右邊顯示一個(gè)對(duì)應(yīng)導(dǎo)航的頁面。
大屏幕
路由地址: /invoices/dashboard
+----------------------+---------------------------+
| | |
| Dashboard | |
| | Unpaid: 5 |
+----------------------+ |
| | Balance: $53,543.00 |
| Invoice 01 | |
| | Past Due: 2 |
+----------------------+ |
| | |
| Invoice 02 | |
| | +-------------------+ |
+----------------------+ | | |
| | | + + + | |
| Invoice 03 | | | + | | | |
| | | | | | + | + | |
+----------------------+ | | | | | | | | |
| | +--+-+--+--+--+--+--+ |
| Invoice 04 | |
| | |
+----------------------+---------------------------+
我們思考一下,/invoices 路由地址是適用于兩種屏幕的,在大屏幕上,它是有效路由嗎?它右邊呈現(xiàn)什么內(nèi)容了?
大屏幕
路由地址: /invoices
+----------------------+---------------------------+
| | |
| Dashboard | |
| | |
+----------------------+ |
| | |
| Invoice 01 | |
| | |
+----------------------+ |
| | |
| Invoice 02 | ??? |
| | |
+----------------------+ |
| | |
| Invoice 03 | |
| | |
+----------------------+ |
| | |
| Invoice 04 | |
| | |
+----------------------+---------------------------+
在大屏幕上,/invoices 不是有效路由,但是在小屏幕上是有效路由。為了讓事件更有趣,考慮一些伙伴會(huì)用大屏手機(jī)。他們先縱向方向?yàn)g覽 /invoices ,然后把手機(jī)轉(zhuǎn)向橫向。突然,頁面上有多余的空間來顯示主界面,所以這里我們需要重定向。
React Router 以前版本的靜態(tài)路由為這種情況是不能有可組合的方案。當(dāng)路由是動(dòng)態(tài)的,無論如何,你能聲明式的編寫這個(gè)功能。如果你開始想U(xiǎn)I想路由,不是像靜態(tài)配置那樣,你的直覺會(huì)引導(dǎo)你到下面的代碼:
const App = () => (
<AppLayout>
<Route path="/invoices" component={Invoices}/>
</AppLayout>
)
const Invoices = () => (
<Layout>
{/* 一直顯示的導(dǎo)航 */}
<InvoicesNav/>
<Media query={PRETTY_SMALL}>
{screenIsSmall => screenIsSmall
// 小屏幕時(shí)沒有重定向
? <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
</Switch>
// 大屏幕時(shí)重定向!
: <Switch>
<Route exact path="/invoices/dashboard" component={Dashboard}/>
<Route path="/invoices/:id" component={Invoice}/>
// 重定向
<Redirect from="/invoices" to="/invoices/dashboard"/>
</Switch>
}
</Media>
</Layout>
)
隋著用戶的手機(jī)從縱向旋轉(zhuǎn)到橫向,這段代碼將自動(dòng)重定向它們到 dashboard ,這一組有效路由改變?nèi)Q于移動(dòng)設(shè)備在用戶手中的動(dòng)態(tài)狀態(tài)。
這僅是一個(gè)案例。還有很多其他可以討論的,我們總結(jié)的建議:為了讓你理解React Router ,想想它是組件,不是一個(gè)靜態(tài)路由,思考如何用 React 聲明性可組合性解決問題,因?yàn)閹缀趺總€(gè)"React Router 問題"大概是個(gè)”React 問題“。