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

