React-Router v5文檔翻譯之服務(wù)端渲染

本項(xiàng)目Github地址,歡迎star

目錄

由于服務(wù)端是無狀態(tài)的绞灼,所以服務(wù)端渲染和客戶端渲染并不相同. 最基本的就是我們封裝app時(shí), 使用無狀態(tài)的 < StaticRouter >來代替< BrowserRouter >, 使用來自于服務(wù)端的請(qǐng)求url來匹配路由懦趋。接下來我們會(huì)討論 context 屬性

// client
<BrowserRouter>
  <App/>
</BrowserRouter>

// server (not the complete story)
<StaticRouter
  location={req.url}
  context={context}
>
  <App/>
</StaticRouter>

當(dāng)你在客戶端渲染 < Redirect >, 瀏覽器地址欄會(huì)改變狀態(tài)使我們能看到新的頁(yè)面,然而在一個(gè)靜態(tài)的服務(wù)環(huán)境下, 我們不能夠改變app的狀態(tài)。代替的是, 我們將渲染的結(jié)果賦給context屬性. 如果我們找到了 context.url, 那么我們知道這個(gè)app重定向了. 這允許我們向服務(wù)端發(fā)送一個(gè)重定向請(qǐng)求

const context = {}
const markup = ReactDOMServer.renderToString(
  <StaticRouter
    location={req.url}
    context={context}
  >
    <App/>
  </StaticRouter>
)

if (context.url) {
  // Somewhere a `<Redirect>` was rendered
  redirect(301, context.url)
} else {
  // we're good, send the response
}

添加明確的應(yīng)用內(nèi)容信息

路由只能添加 context.url. 但是你可能想要發(fā)送重定向的301或302的響應(yīng)。或許你在某些特殊的UI渲染后需要發(fā)送一個(gè)404響應(yīng), 又或者在客戶端沒有認(rèn)證的情況下發(fā)送401。 context屬性是屬于你的, 所以你可以任意改變她. 下面是分辨301與302重定向的方法凸舵。

const RedirectWithStatus = ({ from, to, status }) => (
  <Route render={({ staticContext }) => {
    // there is no `staticContext` on the client, so
    // we need to guard against that here
    if (staticContext)
      staticContext.status = status
    return <Redirect from={from} to={to}/>
  }}/>
)

// somewhere in your app
const App = () => (
  <Switch>
    {/* some other routes */}
    <RedirectWithStatus
      status={301}
      from="/users"
      to="/profiles"
    />
    <RedirectWithStatus
      status={302}
      from="/courses"
      to="/dashboard"
    />
  </Switch>
)

// on the server
const context = {}

const markup = ReactDOMServer.renderToString(
  <StaticRouter context={context}>
    <App/>
  </StaticRouter>
)

if (context.url) {
  // can use the `context.status` that
  // we added in RedirectWithStatus
  redirect(context.status, context.url)
}

404, 401, 或其他狀態(tài)

我們現(xiàn)在可以做到和上面一樣的事,創(chuàng)建一個(gè)包含想要內(nèi)容的組件失尖,當(dāng)收到不同的的狀態(tài)碼時(shí)可以在應(yīng)用的任何地方渲染該組件啊奄。

function Status({ code, children }) {
  return (
    <Route
      render={({ staticContext }) => {
        if (staticContext) staticContext.status = code;
        return children;
      }}
    />
  );
}

現(xiàn)在,當(dāng)你想要給靜態(tài)內(nèi)容添加一個(gè)狀態(tài)碼時(shí)雹仿,你可以在應(yīng)用的任何地方渲染一種狀態(tài)增热。

function NotFound() {
  return (
    <Status code={404}>
      <div>
        <h1>Sorry, can’t find that.</h1>
      </div>
    </Status>
  );
}

// somewhere else
<Switch>
  <Route path="/about" component={About} />
  <Route path="/dashboard" component={Dashboard} />
  <Route component={NotFound} />
</Switch>;

組合所有內(nèi)容

雖然這不是一個(gè)真正的應(yīng)用,但是她展現(xiàn)了將所有內(nèi)容組合在一起所需的常規(guī)部分

import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from './App'

createServer((req, res) => {
  const context = {}

  const html = ReactDOMServer.renderToString(
    <StaticRouter
      location={req.url}
      context={context}
    >
      <App/>
    </StaticRouter>
  )

  if (context.url) {
    res.writeHead(301, {
      Location: context.url
    })
    res.end()
  } else {
    res.write(`
      <!doctype html>
      <div id="app">${html}</div>
    `)
    res.end()
  }
}).listen(3000)

然后是客戶端

import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

ReactDOM.render((
  <BrowserRouter>
    <App/>
  </BrowserRouter>
), document.getElementById('app'))

數(shù)據(jù)加載

要做到這一點(diǎn)有很多不同的方法胧辽,對(duì)此并沒有最佳的實(shí)踐。所以我們尋求多種方法的不同組合方式公黑,而不是規(guī)定或傾向某一種邑商。我們相信React Router可以在你的應(yīng)用的規(guī)則限制下找到一種合理的方式。

最主要的約束是你希望在頁(yè)面渲染前加載完數(shù)據(jù)凡蚜。React Router暴露了一個(gè)matchPath靜態(tài)函數(shù)人断,你可以用她來進(jìn)行路由匹配。你可以在服務(wù)端用這個(gè)函數(shù)來確定哪些依賴的數(shù)據(jù)是要在渲染前完成的朝蜘。

這種方法的特點(diǎn)是在進(jìn)行實(shí)際跳轉(zhuǎn)前設(shè)定好靜態(tài)匹配規(guī)則恶迈,在實(shí)際跳轉(zhuǎn)前就已經(jīng)知道要使用哪些數(shù)據(jù)。

const routes = [
  { path: '/',
    component: Root,
    loadData: () => getSomeData(),
  },
  // etc.
]

然后使用這些規(guī)則在應(yīng)用中渲染你的路由

import { routes } from './routes'

const App = () => (
  <Switch>
    {routes.map(route => (
      <Route {...route}/>
    ))}
  </Switch>
)

在服務(wù)端你可能會(huì)做這些谱醇;

import { matchPath } from 'react-router-dom'

// inside a request
const promises = []
// use `some` to imitate `<Switch>` behavior of selecting only
// the first to match
routes.some(route => {
  // use `matchPath` here
  const match = matchPath(req.url, route)
  if (match)
    promises.push(route.loadData(match))
  return match
})

Promise.all(promises).then(data => {
  // do something w/ the data so the client
  // can access it then render the app
})

最后暇仲,客戶端需要獲取數(shù)據(jù)。我們并不是給你的應(yīng)用規(guī)定數(shù)據(jù)加載的模式副渴,但這些是在開發(fā)中常用的形式奈附。

你可能會(huì)對(duì)我們的進(jìn)行數(shù)據(jù)加載和靜態(tài)路由配置的React Router Config包感興趣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末煮剧,一起剝皮案震驚了整個(gè)濱河市斥滤,隨后出現(xiàn)的幾起案子将鸵,更是在濱河造成了極大的恐慌,老刑警劉巖佑颇,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顶掉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡挑胸,警方通過查閱死者的電腦和手機(jī)一喘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗜暴,“玉大人凸克,你說我怎么就攤上這事∶屏ぃ” “怎么了萎战?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)舆逃。 經(jīng)常有香客問我蚂维,道長(zhǎng),這世上最難降的妖魔是什么路狮? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任虫啥,我火速辦了婚禮,結(jié)果婚禮上奄妨,老公的妹妹穿的比我還像新娘涂籽。我一直安慰自己,他們只是感情好砸抛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布评雌。 她就那樣靜靜地躺著,像睡著了一般直焙。 火紅的嫁衣襯著肌膚如雪景东。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天奔誓,我揣著相機(jī)與錄音斤吐,去河邊找鬼。 笑死厨喂,一個(gè)胖子當(dāng)著我的面吹牛和措,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杯聚,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼臼婆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了幌绍?” 一聲冷哼從身側(cè)響起颁褂,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤故响,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后颁独,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彩届,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年誓酒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了樟蠕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡靠柑,死狀恐怖寨辩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歼冰,我是刑警寧澤靡狞,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站隔嫡,受9級(jí)特大地震影響甸怕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腮恩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一梢杭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秸滴,春花似錦武契、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至内颗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間敦腔,已是汗流浹背均澳。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留符衔,地道東北人找前。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像判族,于是被迫代替她去往敵國(guó)和親躺盛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355