摘要:踩坑幾乎一整年沒咋寫文章,主要是懶,加上工作也挺忙。遇到一些坑,也有一些收獲這里記錄一下。個人習慣使用啟動服務。總結說了上面那么多,其實官方文檔里都有相關例子,就當我的個人踩坑記錄吧。
Next.js踩坑
幾乎一整年沒咋寫文章,主要是懶,加上工作也挺忙。但是想趁著年底發一篇,希望明年更勤奮一點。其實不是沒東西寫,就是想深入一個東西還是很困難的,要查各種資料,最終還是懶就是了。
next.js是react的同構庫,很多文章里把他當作一個腳手架,也不是不行,但是個人認為next.js比一般的腳手架能做的更多,但也有局限性。這兩天下班回去實踐了一下nextjs的開發。遇到一些坑,也有一些收獲這里記錄一下。
請求數據nextjs沒有客戶端的生命周期,只有一個靜態方法getInitialProps,所以獲取接口數據也只能在這個方法里了。getInitialProps的返回數據就作為該組件的props。getInitialProps有兩個參數:req和res,也就是我們非常熟悉的http參數。說句題外話,現有的node web框架都是req作為輸入,res作為輸出,增加各種中間件。
所以個人覺得nextjs的組件形式太適合無狀態組件了。下面是一個簡單的例子代碼:
// 獲取電影列表并渲染 class MovieList extends Component { static async getInitialProps(){ const data = await getMovieList() return { list: data } } render () { return ({this.props.list.map(movie => {) } }})}
當然這里最終僅僅是服務端輸出的列表,我們可能還會有其他操作,比如刪除加載下一頁之類的,但是這些操作都沒必要在服務端操作的。添加幾個相應的方法即可。
路由管理nextjs的路由是基于文件系統的,相當清晰和簡單,比如在pages文件夾下面增加一個movie-detail組件,并寫上相應的代碼,我們就可以訪問/movie-detail 這個路由了。起初覺得這樣的路由形式實在太優雅了,但是用久了就會發現很多問題。
路由嵌套首先是嵌套路由,比如我想建立/user/profile這個路由,這個其實很好解決,就是在pages文件夾下面依次嵌套就行了:
具名路由其次是沒有官方實現具名路徑,什么是具名路徑呢?就是/movie/:id這里這種形式,個人感覺nextjs在這方面是追隨react-router4的。vuejs的同構框架nuxtjs則不存在這個問題,因為vue-router本身也是統一管理路由的。先不說這種情況的好壞,還是找找解決方案吧。
根據我找到的實例和文檔,目前有兩種解決方案:
使用query代替具名路下圖可以看到其實在nextjs router里query是存在的。
那我們需要訪問具名路由頁面的時候可以這么寫, 將id用query傳過去/movie-detail?id=xxx:
// 電影詳情頁面 class MovieDetail extends Component { static async getInitialProps({ req }) { const { id } = req.query const detail = await getDetail(id) return { detail } } render () { return ( // do anything you want ) } }custom server 解決
使用query傳參數過去確實可以解決問題,但是太不優雅,與rest的思想也不太符合。所以next社區找到了另一個解決方案,使用custom server。
在說具體方案之前我們我們可以了解一下,說到底nextjs并不是一個生成靜態資源的腳手架,next最終還是要多帶帶部署node服務的。也就是nextjs其實內置了一個http服務,如果我們不使用custom sever的話,內置服務還是可以很好的幫我們完成渲染頁面的任務。
但是如果我們的node不僅僅是渲染頁面,還需要寫接口。那么這時候的情況就很類似傳統后端的開發模式了:不僅僅需要寫接口還需要渲染頁面。
很顯然nextjs的內置http服務是無法完成這個任務的,我們需要更加完善的web 框架。畢竟專業的事還是交給專業的。這時候就是custom server大顯身手的時候了。nextjs里也有一系列的例子:
那么custom server是如何解決具名路徑的問題的呢?我們是借用nextjs的渲染能力。這里以express為例,具體代碼如下:
// server.js const express = require("express") const next = require("next") const dev = process.env.NODE_ENV !== "production" const app = next({ dev, quiet: false }) const handle = app.getRequestHandler() const SERVE_PORT = process.env.SERVE_PORT || 8001 app.prepare().then(() => { const server = express() server.get("/movie-detail/:id", async (req, res) => { // 渲染movie-detail這個組件 const html = await app.renderToHTML(req, res, "/movie-detail", req.query) res.send(html) }) server.get("*", (req, res) => handle(req, res)) server.listen(SERVE_PORT, err => { if (err) throw err console.log(`> Ready on http://localhost:${SERVE_PORT}`) }) })
上面是server.js的簡略代碼,當然在組件里我們也要做相應處理,代碼如下
// /pages/movie-detail.jsx // 電影詳情頁面 class MovieDetail extends Component { static async getInitialProps({ req }) { const { id } = req.params const detail = await getDetail(id) return { detail, id } } render () { return ( // do anything you want ) } }頁面緩存
對于csr的的react應用來說,渲染耗時100ms并不是什么太大問題,但是到了服務端,100ms很明顯是沒法忍受的。首先客戶端渲染并不會造成服務器資源的浪費,其實也不會對服務器造成太大鴨梨。但是服務端就不一樣了。一旦用戶量大了,勢必會引起各種問題,所以頁面緩存還是很有必要的。
具體頁面緩存在哪里并不是我們考量的范圍,同樣頁面緩存也需要用到custom server,具體服務端框架自定吧。這里以lru-cache為例做一個簡單的頁面緩存,其實換成其他的諸如redis也是沒有任何問題的。
const dev = process.env.NODE_ENV !== "production" const next = require("next") const express = require("express") const LRUCache = require("lru-cache") const ssrCache = new LRUCache({ max: 1000, // cache item count maxAge: 1000 * 60 * 60, // 1 hour }) const app = next({ dev, quiet: false }) const handle = app.getRequestHandler() const SERVE_PORT = process.env.SERVE_PORT || 8001 app.prepare().then(() => { const server = express() server.get("/", async (req, res) => { renderAndCache(req, res, "/", { ...req.query }) }) server.get("/movie-detail/:id", async (req, res) => { renderAndCache(req, res, "/movie-detail", { ...req.query }) }) server.get("*", (req, res) => handle(req, res)) server.listen(SERVE_PORT, err => { if (err) throw err console.log(`> Ready on http://localhost:${SERVE_PORT}`) }) }) const getCacheKey = req => `${req.url}` // 緩存并渲染頁面,具體是重新渲染還是使用緩存 async function renderAndCache(req, res, pagePath, queryParams) { const key = getCacheKey(req) if (ssrCache.has(key)) { res.setHeader("x-cache", "HIT") res.send(ssrCache.get(key)) return } try { const html = await app.renderToHTML(req, res, pagePath, queryParams) // Something is wrong with the request, let"s skip the cache if (res.statusCode !== 200) { res.send(html) return } // Let"s cache this page ssrCache.set(key, html) res.setHeader("x-cache", "MISS") res.send(html) } catch (err) { app.renderError(err, req, res, pagePath, queryParams) } }
其中renderAndCache是關鍵。這里判斷頁面是否有緩存,如果有的話則直出緩存內容。否則的話就重新渲染。至于緩存時間還有緩存大小看個人設置了,這里不贅述了。
部署上線部署上線這一塊實在沒什么好說的,簡單的話直接起一個node服務的就可以,復雜一點就要包括報警重啟等等,都是看個人情況的。
個人習慣使用supervisor啟動node服務。
總結說了上面那么多,其實官方文檔里都有相關例子,就當我的個人踩坑記錄吧。
對于nextjs來說,我認為如果是展示型的應用,就應該放心大膽的用起來。不光開發快還爽,同時屏蔽webpack配置,有什么理由不用?
如果是功能性的,比如一系列的繪圖組件則完成沒必要使用了,對于canvas之類的還是必須用客戶端渲染,然而nextjs又沒有生命周期,用nextjs可能會相當坑。
對于個人開發這我則是相當推薦。何必去配置webpack浪費生命啊。
如果是完全靜態的應用,我推薦gatsbyjs。具體怎么使用則是另外一個話題了。
如有謬誤,輕點噴。 over
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/101514.html
摘要:接下來我們運行一下。因此,我們需要新建一個目錄。接下在再重新啟動一下試試。因為默認開啟服務端渲染,也就無需我們進行任何的配置,因此現在這個極其簡單的應用就是一個。代碼地址參考文章服務端渲染與打造高可靠與高性能的同構解決方案 寫在前面 說實話,我個人還是覺得文筆越來越不錯了,以前的文章都是一個問題悶到天黑,文章寫的有點亂由于文章過于龐大導致不是一氣呵成的,思路有時候會很混亂。所以我也準備...
摘要:官方也有一個的工具,但是只能簡單的安裝基礎的依賴,或者通過他們提供的某個例子來構建自己的項目。由于目前還在開發階段只支持上面這些的配置也是平常我用的比較多的配置。 因為公司的業務需求現在開發都用nextjs來實現React的服務端渲染,為了之后開發方便自己寫了個腳手架工具。 官方也有一個create-next-app的工具,但是只能簡單的安裝基礎的依賴,或者通過他們提供的某個例子來構建...
摘要:樣式在中寫樣式,一般可以歸為類,一類是基于文件的傳統方式包括,等,另一類則是。我們回到我們的代碼中,更改,代碼如下在標簽中,我們寫我們的,必須包含在中,否則會報錯。至此,的基礎概念已經介紹完了,更高級的用法,可以參考官方的例子。 本篇教程基于上一篇的基礎,主要講解服務端渲染,樣式以及部署相關的一些知識,若你沒有看過上一篇的內容,或者你看過又忘了,建議重新去看一遍。 順便說一句,Next...
摘要:是一個基于實現的服務端渲染框架,地址為。本文先從簡單地基礎概念開始,一步一步帶大家認識。本篇教程到此結束,后面會跟大家介紹的服務端渲染及以及部署相關的一下概念及示例代碼。 Next.js是一個基于React實現的服務端渲染框架,github地址為next.js。 使用Next.js實現服務端渲染是一件非常簡單的事,在這里,你完全可以不用自己去寫webpack等配置,Next.js全都幫...
摘要:中文站點中文站當前翻譯版本為。注意將不能使用在子組件中。只能使用在頁面中。替換路由組件默認將新推入路由棧中。以防服務端渲染發生錯誤,建議事件寫在生命周期里。禁止文件路由默認情況,將會把下的所有文件匹配路由如渲染為如果你的項目使用 Next.js 是一個輕量級的 React 服務端渲染應用框架。 Next.js中文站點 http://nextjs.frontendx.cn Next.j...
閱讀 2242·2021-11-17 09:33
閱讀 2783·2021-11-12 10:36
閱讀 3406·2021-09-27 13:47
閱讀 895·2021-09-22 15:10
閱讀 3494·2021-09-09 11:51
閱讀 1399·2021-08-25 09:38
閱讀 2762·2019-08-30 15:55
閱讀 2613·2019-08-30 15:53