56.React學(xué)習(xí)筆記.SSR渲染

為什么需要SSR?

SSR: Server side rendering服務(wù)端渲染, 指的是頁(yè)面在服務(wù)器端已經(jīng)生成了完成的html頁(yè)面結(jié)構(gòu), 不需要瀏覽器解析.
單頁(yè)面富應(yīng)用, index.html, 剛開(kāi)始基本沒(méi)東西.

  • 首屏加載速度慢, 剛開(kāi)始的時(shí)候是空白的, index.html下載之后(前端渲染的時(shí)候是瀏覽器來(lái)進(jìn)行的, 可以交給服務(wù)端node操作):
    1. 需要先請(qǐng)求并執(zhí)行js文件
    2. 發(fā)送ajax
    3. 獲取數(shù)據(jù)并生成html結(jié)構(gòu)渲染(ssr從瀏覽器轉(zhuǎn)到Nodejs)
  • SEO搜索引擎優(yōu)化, 初始頁(yè)面獲取不到相應(yīng)權(quán)重信息.

補(bǔ)充概念:
同構(gòu)應(yīng)用: 一套既可以在服務(wù)端, 又可以在客戶端運(yùn)行的代碼.

  • 同構(gòu)是一種ssr的形態(tài), 是現(xiàn)代ssr的一種表現(xiàn)形式
  • 當(dāng)用戶發(fā)出請(qǐng)求時(shí), 現(xiàn)在服務(wù)器通過(guò)ssr渲染出首頁(yè)的內(nèi)容
  • 但是對(duì)應(yīng)的代碼同樣可以在客戶端被執(zhí)行
  • 執(zhí)行的目的包括事件綁定等, 以及其他頁(yè)面切換時(shí)也可以在客戶端被渲染

使用SSR的方式

方式一: 手動(dòng)搭建SSR框架;
方式二: 使用已經(jīng)成熟的SSR框架: Next.js (用于react);

  1. 安裝Next.js腳手架:
    npm install -g create-next-app
  2. 創(chuàng)建Next.js項(xiàng)目
    create-next-app next-demo

創(chuàng)建好的項(xiàng)目目錄如下:


image.png
  • pages下每個(gè)文件就是一個(gè)頁(yè)面, 相當(dāng)于是一個(gè)路由映射(next已經(jīng)幫我們配置好了后端路由)

這里我們手動(dòng)添加了About頁(yè)面, 并且在index.js里面提供了跳轉(zhuǎn).
如果我不想每次都發(fā)很多請(qǐng)求去獲取頁(yè)面, 那么我們可以用另一種方式來(lái)進(jìn)行前端渲染, 直接跳轉(zhuǎn)到About頁(yè).

  • 使用next/link包里面的Link組件, 下圖可以看到,我們請(qǐng)求的是同服務(wù)器下被打包好的about.js文件.


    image.png
  • webpack-hmr?page=/about更改當(dāng)前路由進(jìn)行頁(yè)面跳轉(zhuǎn), 根據(jù)about進(jìn)行前端渲染.
      // 這里L(fēng)ink只是作為功能來(lái)使用, 里面最好添加相應(yīng)的子元素
      <Link href="/about">
        <a>關(guān)于</a>
      </Link>

頁(yè)面標(biāo)題

通常我們希望每一個(gè)頁(yè)面都有自己的標(biāo)題, 而不是什么localhost路徑.

  • 通過(guò)next/head導(dǎo)出的Head組件來(lái)完成, 這個(gè)組件會(huì)被加載到當(dāng)前頁(yè)面的head標(biāo)簽中
  • 同理, 對(duì)應(yīng)的logo也是這么做
      <Head>
        <title>wwqwwqwwq</title>
      </Head>

共享組件(實(shí)際上是個(gè)高階組件)

有時(shí)候我們想要不同頁(yè)面的head和footer是一樣的, 但如果沒(méi)有其他方式, 我們只能每個(gè)文件都去添加這么兩個(gè)組件, 重復(fù)代碼太多.

  • 這里我們?cè)陧?xiàng)目頂層進(jìn)行共享組件抽離.


    AppLayout

    主頁(yè)

    Index

    About

還有另一種方法是將共享組件放在_app.js(框架在這里渲染index)文件中使用


image.png

_document.js文件

在這個(gè)文件中可以對(duì)我們的html文檔進(jìn)行自定義, 官網(wǎng)鏈接https://www.nextjs.cn/docs/advanced-features/custom-document.

image.png

結(jié)構(gòu)解析

  • Html組件就是我們?cè)阡秩緯r(shí)我們?cè)诳刂婆_(tái)Elements下看到的html
  • Main是我們App中寫的所有內(nèi)容
    修改后記得重新yarn dev編譯啟動(dòng)一下

相關(guān)樣式添加

在react中有三種樣式, 普通css, module.css, css in js.(筆者個(gè)人喜歡使用styled-components)

// 全局
import "../styles/app.css";
// 模塊
import styles from '../styles/Home.module.css';
// 生效
<h1 className={styles.title}>Home頁(yè)面</h1>
// 不生效
<h1 className='title'>測(cè)試</h1> 
// styled-jsx, 筆者寫起來(lái)很難受...
      <style>{`
        p {
          color: blue;
          text-decoration: underline;
        }
      `}</style>
  1. 全局樣式可以直接import到_app文件下.
  2. 模塊樣式import到相應(yīng)的文件, 然后通過(guò)className綁定到對(duì)應(yīng)的元素上面. 這種方式相當(dāng)于一個(gè)模塊, 在哪里使用在哪里綁定才會(huì)生效.
  3. styled-jsx(用起來(lái)像vue): 一種css in js的技術(shù), 在nextjs中默認(rèn)集成, 會(huì)使用的話就不需要單獨(dú)安裝styled-components, 但筆者還是喜歡使用styled-components...


    image.png
  4. 使用styled-components: 一般情況對(duì)每個(gè)頁(yè)面要單獨(dú)創(chuàng)建一個(gè)文件夾, 這樣顯得項(xiàng)目比較有條理.
  • 這里有個(gè)問(wèn)題需要留意一下, 因?yàn)槲覀?strong>通過(guò)<Link />來(lái)進(jìn)行跳轉(zhuǎn)的時(shí)候?qū)儆贑SR客戶端渲染, 但如果強(qiáng)硬刷新頁(yè)面的時(shí)候?qū)儆诜?wù)端渲染, 這時(shí)候就會(huì)有問(wèn)題了. 這個(gè)時(shí)候會(huì)提示匹配對(duì)應(yīng)的className屬性, 因?yàn)槟J(rèn)情況下, 服務(wù)端不會(huì)給類名進(jìn)行匹配的.
  • 但在nextjs中可以通過(guò)插件(babel-plugin-styled-components用于styled-components在服務(wù)端渲染時(shí)正常生效)進(jìn)行一個(gè)特殊的配置, 在babel轉(zhuǎn)化的時(shí)候, 對(duì)styled js進(jìn)行正確的轉(zhuǎn)化, 這個(gè)屬于devDependencies.
  • 我們?cè)诟夸浵聞?chuàng)建.babelrc文件(進(jìn)行babel轉(zhuǎn)化時(shí)會(huì)讀取這個(gè)文件, 運(yùn)行編譯時(shí)), 改了配置記得重新yarn dev.
{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    "styled-components"
  ]
}
image.png

路由嵌套

之前我們已經(jīng)知道, 每個(gè)文件對(duì)應(yīng)一個(gè)路由信息.
所以我們使用的時(shí)候, 在對(duì)應(yīng)組件的文件夾下, 再創(chuàng)建對(duì)應(yīng)的組件(/文件夾)即可.

頁(yè)面跳轉(zhuǎn)中參數(shù)的傳遞

第一種方式: Link標(biāo)簽
當(dāng)我們點(diǎn)擊推薦列表中的某一項(xiàng)時(shí), 我們希望url跳轉(zhuǎn)后, 頁(yè)面進(jìn)行同步.
react中我們可以使用/recommend/:id來(lái)進(jìn)行參數(shù)傳遞, 但在nextjs中怎么使用呢?
使用query參數(shù)的方式/recomend?id=${item}, 這里我們可以看到, 對(duì)應(yīng)的參數(shù)已經(jīng)傳到url里面了.

image.png

接下來(lái)如何使用呢? 通過(guò)next/router導(dǎo)出的useRouter, 截圖可以看到這樣是成功的.

import { useRouter } from "next/router";
const route = useRouter();
<h2>Recommend: {router.query.id}</h2>

image.png

第二種方式: 代碼跳轉(zhuǎn)
除了第一種Link標(biāo)簽跳轉(zhuǎn), 還有另一種代碼跳轉(zhuǎn)的方式.

// index.js
import Router from "next/router";
  const recommendItemClick = (item) => {
    Router.push({
      pathname: "/recommend",
      query: {
        id: item,
      },
    });
  };
  <li key={item} onClick={(e) => recommendItemClick(item)}>
    推薦數(shù)據(jù): id{item}
  </li>
// ./recommend/index.js
  const router = useRouter();
  <h2>Recommend: {router.query.id}</h2>

在頁(yè)面中發(fā)送網(wǎng)絡(luò)請(qǐng)求(可以在瀏覽器,也可以在服務(wù)器中執(zhí)行)

這里我們需要注意一點(diǎn), 不能像在react中在useEffect中發(fā)請(qǐng)求然后存到useState中, 因?yàn)樵诜?wù)端渲染時(shí), 在第一次渲染時(shí)已經(jīng)渲染好了.
當(dāng)我們使用useState再渲染時(shí), 服務(wù)端是不會(huì)幫我們做的.
如果我們確實(shí)想要在頁(yè)面中請(qǐng)求一些數(shù)據(jù), 那網(wǎng)絡(luò)請(qǐng)求的代碼應(yīng)該放在哪里?

  • 我們通過(guò)index.js組件Home的getInitialProps屬性進(jìn)行操作, 將其賦值為一個(gè)函數(shù), 這個(gè)函數(shù)會(huì)在組件第一次渲染前進(jìn)行, 可以是一個(gè)異步操作.
Home.getInitialProps = async (props) => {
  const res = await axios.get({
    url: "接口",
  });
  return {
    name: "wwq",
    banners: res.data.data.banner.list,
    recommends: res.data.data.recommend.list,
  };
};
  <h2>輪播圖數(shù)據(jù):</h2>
    <ul>
      {banners.map((item, index) => {
        return <li key={item?.acm}>{item.title}</li>;
      })}
    </ul>
  • 這里我們r(jià)eturn的對(duì)象在Home組件里頭是可以獲取到的, 然后我們?cè)趐ostman中進(jìn)行測(cè)試, 可以看到, 對(duì)應(yīng)的數(shù)據(jù)是成功渲染出來(lái)的.


    image.png

這里只是簡(jiǎn)單分享一下react的ssr入門是怎么進(jìn)行的, 如果有進(jìn)一步開(kāi)發(fā)需求或進(jìn)階需求, 可以移步nextjs官網(wǎng).

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末髓绽,一起剝皮案震驚了整個(gè)濱河市隙姿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖婆跑,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異翎朱,居然都是意外死亡熏矿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門孝凌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人月腋,你說(shuō)我怎么就攤上這事蟀架。” “怎么了榆骚?”我有些...
    開(kāi)封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵片拍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我妓肢,道長(zhǎng)捌省,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任碉钠,我火速辦了婚禮纲缓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘喊废。我一直安慰自己祝高,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布污筷。 她就那樣靜靜地躺著工闺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瓣蛀。 梳的紋絲不亂的頭發(fā)上陆蟆,一...
    開(kāi)封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音惋增,去河邊找鬼叠殷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛器腋,可吹牛的內(nèi)容都是我干的溪猿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼纫塌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼诊县!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起措左,我...
    開(kāi)封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤依痊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胸嘁,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓶摆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了性宏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片群井。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖毫胜,靈堂內(nèi)的尸體忽然破棺而出书斜,到底是詐尸還是另有隱情,我是刑警寧澤酵使,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布荐吉,位于F島的核電站,受9級(jí)特大地震影響口渔,放射性物質(zhì)發(fā)生泄漏样屠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一缺脉、第九天 我趴在偏房一處隱蔽的房頂上張望痪欲。 院中可真熱鬧,春花似錦攻礼、人聲如沸勤揩。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)陨亡。三九已至,卻和暖如春深员,著一層夾襖步出監(jiān)牢的瞬間负蠕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工倦畅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遮糖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓叠赐,卻偏偏與公主長(zhǎng)得像欲账,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子芭概,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容