React之服務(wù)端渲染
前言
前面給大家探討過(guò)vue的服務(wù)端渲染,今天就通過(guò)本文帶領(lǐng)大家一起認(rèn)識(shí)關(guān)于react的服務(wù)端渲染知識(shí)。
開(kāi)始之前先帶領(lǐng)大家回顧一下什么是服務(wù)端渲染,為什么要服務(wù)端渲染這些問(wèn)題!
什么是服務(wù)器端渲染
服務(wù)器端渲染簡(jiǎn)稱(chēng) SSR(server side render),就是在服務(wù)器端將數(shù)據(jù)和 HTML 融合后返回給瀏覽器
使用 React 構(gòu)建客戶(hù)端應(yīng)用程序,默認(rèn)情況下,可以在瀏覽器中輸出 React 組件,進(jìn)行生成 DOM 和操作 DOM。React 也可以在服務(wù)端通過(guò) Node.js 轉(zhuǎn)換成 HTML,直接在瀏覽器端“呈現(xiàn)”處理好的 HTML 字符串,這個(gè)過(guò)程可以被認(rèn)為 “同構(gòu)”,因?yàn)閼?yīng)用程序的大部分代碼都可以在服務(wù)器和客戶(hù)端上運(yùn)行。
為什么使用服務(wù)器端渲染
與傳統(tǒng) SPA(Single Page Application - 單頁(yè)應(yīng)用程序)相比,服務(wù)器端渲染(SSR)的優(yōu)勢(shì)主要在于:
1.vue,angular,react等都為spa應(yīng)用框架,按照常規(guī)的渲染,數(shù)據(jù)是異步渲染的,這樣的話(huà)不利于搜索引擎爬蟲(chóng)抓取,不信你看看頁(yè)面源碼里是否有數(shù)據(jù)渲染。
2.更好的用戶(hù)體驗(yàn),對(duì)于緩慢的網(wǎng)絡(luò)情況或運(yùn)行緩慢的設(shè)備,加載完資源瀏覽器直接呈現(xiàn),無(wú)需等待所有的 JavaScript 都完成下載并執(zhí)行,才顯示服務(wù)器渲染的HTML。
服務(wù)端渲染的弊端
1.由于服務(wù)端與瀏覽器客戶(hù)端環(huán)境區(qū)別,選擇一些開(kāi)源庫(kù)需要注意,部分庫(kù)是無(wú)法在服務(wù)端執(zhí)行,比如你有 document、window 等對(duì)象獲取操作,都會(huì)在服務(wù)端就會(huì)報(bào)錯(cuò),所以在選擇的開(kāi)源庫(kù)要做甄別。
2.使用服務(wù)端渲染,比如要起一個(gè)專(zhuān)門(mén)在服務(wù)端渲染的服務(wù),與之前,只管客戶(hù)端所需靜態(tài)資源不同,你還需要 Node.js 服務(wù)端的和運(yùn)維部署的知識(shí),對(duì)你所需要掌握的知識(shí)點(diǎn)要求更多 服務(wù)器需要更多的負(fù)載,在 Node.js 中完成渲染,由于 Node.js 的原因大量的CPU資源會(huì)被占用。
服務(wù)端渲染和客戶(hù)端渲染的區(qū)別
客戶(hù)端渲染路線(xiàn):
1.請(qǐng)求html
2.服務(wù)端返回html
3.瀏覽器下載html里面的js/css文件
4.等待js文件下載完成
5.等待js加載并初始化完成
6.js代碼可以運(yùn)行后由js代碼向后端請(qǐng)求數(shù)據(jù)( ajax/fetch )
7.等待后端數(shù)據(jù)返回
8.react-dom( 客戶(hù)端 )從無(wú)到完整地,把數(shù)據(jù)渲染為響應(yīng)頁(yè)面
服務(wù)端渲染路線(xiàn):
1.請(qǐng)求html
2.服務(wù)端請(qǐng)求數(shù)據(jù)
3.服務(wù)器初始渲染(服務(wù)端性能好,較快)
4.服務(wù)端返回已經(jīng)有正確內(nèi)容的頁(yè)面
5.客戶(hù)端請(qǐng)求js/css文件
6.等待js文件下載完成
7.等待js加載并初始化完成
8.react-dom( 客戶(hù)端 )把剩下一部分渲染完成( 內(nèi)容小,渲染快 )
React服務(wù)端渲染之Next.js
本文主要講的是針對(duì)react進(jìn)行服務(wù)端渲染的next.js,它跟vue的nuxt.js一樣,可以不需要大量改造現(xiàn)有的項(xiàng)目代碼,從而實(shí)現(xiàn)服務(wù)端渲染,本文就帶領(lǐng)大家一起來(lái)認(rèn)識(shí)它吧!
Next.js 是一個(gè)輕量級(jí)的 React 服務(wù)端渲染應(yīng)用框架。
next.js的特性:
1.以文件系統(tǒng)為基礎(chǔ)的客戶(hù)端路由(File-System Routing)
2.代碼自動(dòng)分隔使頁(yè)面加載更快(Automatic Code Splitting)
3.默認(rèn)服務(wù)端渲染模式(Server Side Rendering)
4.開(kāi)發(fā)環(huán)境支持模塊熱替換(Hot Module Replacement)
5.支持JSX和ES6語(yǔ)法
6.支持typescript
7.可以運(yùn)行在Express和其他Node.js的HTTP 服務(wù)器上
8.可以定制化專(zhuān)屬的babel和webpack配置
開(kāi)始構(gòu)建一個(gè)Next.js項(xiàng)目?
在命令行工具中依次執(zhí)行下面語(yǔ)句:
// 在本地創(chuàng)建一個(gè)項(xiàng)目跟目錄$ mkdir hello-next// 切換到項(xiàng)目根目錄$ cd hello-next// 用npm初始化項(xiàng)目$ npm init -y// 將react和next安裝到本地依賴(lài)$ npm install --save react react-dom next// 創(chuàng)建文件夾 pages$ mkdir pages
創(chuàng)建完文件夾之后,打開(kāi)hello-next文件下的package.json文件,在 scripts 下添加一個(gè)script,如下:
{"scripts": {"dev": "next"}}
項(xiàng)目準(zhǔn)備工作完成,運(yùn)行下面這條命令開(kāi)啟項(xiàng)目服務(wù)器:
$ npm run dev創(chuàng)建第一個(gè)頁(yè)面
在 pages 目錄下創(chuàng)建一個(gè)名稱(chēng)為 index.js 的文件, 內(nèi)容如下:
const Index = () => {Hell Next.js
}export default Index
現(xiàn)在, 再次訪(fǎng)問(wèn) http://localhost:3000, 在頁(yè)面上你會(huì)看到 “Hello Next.js”. 這里, 我們只是從 pages/index.js 模塊導(dǎo)出了一個(gè)簡(jiǎn)單的 React 組件. 同理, 可以編寫(xiě)你自己的模塊并且導(dǎo)出它.
next路由
所有的頁(yè)面的路由都是通過(guò)后端服務(wù)器來(lái)控制的,要想實(shí)現(xiàn)客戶(hù)端路由,需要借助Next.js的Link API。
我們?cè)陧?xiàng)目根目錄下創(chuàng)建components文件夾,并在該目錄下創(chuàng)建Header和Layout組件公共組件,Header組件用于頁(yè)面導(dǎo)航頭部,Layout組件用于頁(yè)面布局,具體代碼如下如下:
// Header.jsimport Link from 'next/link'const linkStyle = {marginRight: 15}const Header = () => ()export default Header
// Layout.jsimport Header from './Header'const layoutStyle = {margin: 20,padding: 20,border: '1px solid #DDD'}const Layout = (props) => ({props.children})export default Layout
接下來(lái)再修改pages目下的about.js、post.js和index.js文件,把剛剛編寫(xiě)的公共組件用于頁(yè)面布局,修改以后的具體代碼如下:
// about.jsimport Layout from '../components/Layout'export default () => (This is the about page
)
// post.jsimport Layout from '../components/Layout'export default (props) => ({props.url.query.title}
This is the blog post content.
)
// index.jsimport Layout from '../components/Layout'import Link from 'next/link'const PostLink = (props) => ({props.title})export default () => (My Blog
注:可以使用 使鏈接和預(yù)加載在后臺(tái)同時(shí)進(jìn)行,來(lái)達(dá)到頁(yè)面的最佳性能。
路由遮蓋(Route Masking)
Next.js上提供了一個(gè)獨(dú)特的特性:路由遮蓋(Route Masking)。它可以使得在瀏覽器上顯示的是路由A,而App內(nèi)部真正的路由是B。這個(gè)特性可以讓我們來(lái)設(shè)置一些比較簡(jiǎn)潔的路由顯示在頁(yè)面,而系統(tǒng)背后是使用一個(gè)帶參數(shù)的路由。
比如上面的例子中,地址欄中顯示的是 http://localhost:3000/post?title=Hello%20Next.js ,這個(gè)地址含有一個(gè)title參數(shù),看著很不整潔。
我們就可以用Next.js來(lái)改造路由,使用路由遮蓋來(lái)創(chuàng)建一個(gè)更加簡(jiǎn)潔的路由地址。比如我們可以看到在post.js使用了as屬性,該屬性的作用是進(jìn)行路由覆蓋,在不使用該屬性時(shí),在點(diǎn)擊鏈接后瀏覽器地址欄顯示的是http://localhost:3000/post?title=Hello%20Next.js,而使用了as屬性就將該地址改造成 http://localhost:3000/p/hello-nextjs。
請(qǐng)求接口,獲取數(shù)據(jù)
Next.js 在 React 的基礎(chǔ)上為組件添加了一個(gè)新的特性:getInitialProps (有點(diǎn)像是getInitialState),它用于獲取并處理組件的屬性,返回組件的默認(rèn)屬性。我們可以在該方法中請(qǐng)求數(shù)據(jù),獲取頁(yè)面需要的數(shù)據(jù)并渲染返回給前端頁(yè)面。
$ npm install --save isomorphic-unfetch修改 pages/index.js 里的內(nèi)容,換成下面這樣:
import Layout from '../components/MyLayout.js'import Link from 'next/link'import fetch from 'isomorphic-unfetch'const Index = (props) => (Batman TV Shows
{props.shows.map(({show}) => (href={`/post?id=${show.id}`}>{show.name}))})Index.getInitialProps = async function() {const res = await fetch('https://api.tvmaze.com/search/shows?q=batman')const data = await res.json()console.log(`Show data fetched. Count: ${data.length}`)return {shows: data}}export default Index
上述代碼中,在 getInitialProps 中使用了 async 和 await 來(lái)處理異步請(qǐng)求,并將取到的數(shù)據(jù)當(dāng)做一個(gè)屬性賦給頁(yè)面,頁(yè)面拿到這個(gè)屬性的值后會(huì)用于頁(yè)面的初始化渲染。
樣式化組件
Next.js 提供了一個(gè) css-in-js 的特性,它允許你在組件內(nèi)部寫(xiě)一些樣式,你只需要在組件內(nèi)使用標(biāo)簽來(lái)寫(xiě) css 即可。舉個(gè)例子,比如我們?cè)?pages/index.js 里添加樣式:
import Layout from '../components/MyLayout.js'import Link from 'next/link'function getPosts () {return [{id: 'hello-nextjs',title: 'Hello Next.js'},{id: 'learn-nextjs',title: 'Learn Next.js is awesome'},{id: 'deploy-nextjs',title: 'Deploy apps with ZEIT'}]}export default () => (My Blog
{getPosts().map((post) => (href={`/post?title=${post.title}`}>{post.title}))})
在上述代碼中,我們沒(méi)有直接使用 標(biāo)簽來(lái)書(shū)寫(xiě)樣式代碼,而是寫(xiě)在一個(gè)模板字符串({``})里面。Next.js 使用 babel插件來(lái)解析 styled-jsx ,它支持樣式命名空間,未來(lái)還將支持變量賦值。
需要注意的是:styled-jsx 的樣式不會(huì)應(yīng)用到子組件,如果想要該樣式適用于子組件,可以在 styled-jsx 標(biāo)簽添加屬性global:。
結(jié)尾:
好了,到這里基本就把next的搭建,基本使用,路由等介紹完了,已經(jīng)解決的基本使用,洗完能幫助到你,畢竟服務(wù)端渲染在日常中還是很常見(jiàn),比如一些C端產(chǎn)品經(jīng)常需要做服務(wù)端渲染,最典型的就是一些電商網(wǎng)站,所以服務(wù)端渲染這塊的知識(shí)還是建議大家掌握的哈!
- END -
結(jié)伴同行前端路

