react native text换行_基于React+Koa实现React SSR服务端渲染
其實這個概念很早之前就有了解了,出于沒有應用場景原因,之前一直都只停留在了解API的層面,未曾去實踐。快到周末閑來無事,自己復盤了下之前做的新商城,一直在考慮有沒有更好的方案,于是React Server-Side Rendering被很自然的寫到了草稿紙上,一起寫上去的還有egg.js。
總結一句,接入服務端渲染有服務端渲染的好,客戶端渲染有客戶端渲染的更好。
這是背景。
2019.04.12更新
發現我這個react-ssr的github倉庫代碼和這篇文章的思維被掘金的一個博主抄到掘金社區,他那篇文章拿了高贊。他連我倉庫的里前端工程代碼都拿出來寫到博客里,而且沒有備注出處!真希望大家尊重原創性。
2019.04.01 更新
補充一個最終上線完的體驗。
最終線上產品體會;相比于傳統的服務端渲染,React SSR可以做到更完善的體驗;相比于前后端完全分離的SPA,React SSR可以做到首屏更快的得到展示,瀏覽器解析渲染完dom節點既可以展示了。我的個人博客是這個方案實現的(Koa2 + React SSR + Mongdb),可以參考下。
王佳欣的小站?www.shuxia123.com----以下是原文----
問題?
為什么React既可以做browser瀏覽器端的渲染,又可以做server服務端,還可以做native客戶端的渲染呢?
因為React將渲染工作交給了react-dom(瀏覽器渲染)、react-server(服務端渲染)、react-native(客戶端渲染)等渲染器。而React 包只負責定義react,讓我們可以使用react的特性,如:component、createElement、lazy、createContext、createRef等等在特性,這些特性任何平臺都可以正常使用的,不負責具體的渲染工作。
而,各個渲染器中指定了特定的平臺,實現各個平臺的渲染邏輯和平臺特性,如react-dom.render就可以實現dom的渲染。
所以,react就能實現多端渲染,只要在不同的端,引入不同的渲染器就可以了。
好處?
1、可以優化SEO,可以優化首屏白屏的加載時間。
2、不需要開發額外的模板
如果采用使用SSR做node渲染的前后端分離,可能要開發多套模板的,比如:加載更多的情況,就需要做一套node使用的nunjucks模板(用于渲染首屏數據渲染),和一套瀏覽器js使用的模板(用于加載更多時),比較難維護。
采用SSR渲染使用’ react-dom/server’ 的 renderToString對React組件進行渲染的,因此只需要開發一套組件(React 模板),避免了開發多套模板的工作。
3、單頁更好做用戶體驗的優化,這點也很重要。
重新翻閱了React、React-Router服務端渲染的API,
ReactDOMServer – React?reactjs.orgReact Router: Declarative Routing for React?reacttraining.com一:總體大綱
開始動手實踐前,我畫了張大概流程圖,捋了捋思路,我把原圖貼一下,希望有些幫助。
如上圖(有點丑)所示:
Server端(Koa實現)需要做3件事:
Client端(React實現)
模板內定義好要渲染的信息。
- seo信息,title、keyword、description字段信息
- layout信息,既服務端渲染dom內容,ReactDOM.hydrate/render是會用到該節點。
- window['defaultReaderData’]信息,json格式的初始信息,供給React組件在瀏覽器端首次渲染時使用,確保渲染dom與服務端渲染的dom一致。
2. React-Router定義路由,保持與服務端定義的路由一致,所以采用BrowserRouter形式的路由。
3. Redux數據處理,為了使React組件首次渲染dom與服務端渲染的dom一致,所以createStore時,默認數據用window['defaultReaderData’]
4.路由切換時,路由的目標組件,完成數據獲取,與組件的重新創建/更新。
二:開始動手
思路捋清楚了,然就做吧。
服務端開發
服務端依賴比較少,可以瀏覽器訪問接口直接測試,所以從服務端開始。
以首頁和詳情頁為例子。需要實現以下的頁面路由和數據接口路由(RestFul規范)。
1、路由準備
// 頁面路由
http://xxxx.com/
http://xxxx.com/detail/4840388
// 接口路由
http://xxxx.com/api/home
http://xxxx.com/api/movie/1652592
// demo文件 let router = new Router({prefix: '/' }); router.get('/', demoControl.home); router.get('detail/:id', demoControl.detail);// api/demo 文件 let router = new Router({prefix: '/api' }); router.get('/home', ApiControl.fetchHome); router.get('/movie/:id', ApiControl.fetchOneMovie);模板渲染({{ xxx }} 是需要通過服務端渲染的占位符)
模板文件:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>{{ title }}</title><meta name="keywords" content="{{ keyword }}"><meta name="description" content="{{ description }}"> </head> <body>{{ layout | safe }}<script type="text/javascript">window['defaultRenderData'] = {{ data | dump | safe }};</script><script type="text/javascript" src="http://localhost:8088/index.js"></script> </body> </html>渲染模板:
通過React Api文檔,了解到’ react-dom/server’ 的 renderToString 可以在將React組件渲染成字符串,我們可以根據它來構造layout的內容。
renderToString會觸發React組件的constructor和render和componentWillMount方法,然后dom字符串。這也解釋了為什么componentWillMount中setState或者獲取數據會不安全。因為,如果再componentWillMount中或數據獲取的話,那么服務端渲染時可能會導致數據的多次獲取。原文是這樣講的。
The above code is problematic for both server rendering (where the external data won’t be used) and the upcoming async rendering mode (where the request might be initiated multiple times).StaticRouter 的context屬性設置的數據,在Client端匹配路由組件可以通過this.props.staticContext獲取到,這樣方便我們將數據直接輸出到目標組件。
const store = createStore(model.data); const reactDomStr = renderToString(<Provider store={ store }><StaticRouter location={ctx.request.url} context={model.data}><Layout /></StaticRouter></Provider> );ctx.response.body = ENV.render(view, Object.assign(// layout組件節點渲染結果{ layout: reactDomStr },// seo相關model.seo || {},// 服務端渲染的數據{ data: model.data || { home: {} } }) );數據處理:
這邊不做深入介紹了。
客戶端開發:
模板準備
我用webpack做的項目工程,因此只要構建一個html即可。這邊需要注意的是不同環境的配置,以開發環境來說,為了在更新所以在構建模板是,模板引入資源publicPath設為http://localhost:8088/與devServer配置的端口一致。其他環境大家可以看配置文件build/cofig.js
路由準備:
<div id="app" className={className('layout')}><Switch><Route path="/" component={Home} exact /><Route path="/detail/:id" component={Detail} /></Switch> </div>其他的就不做深入,介紹了??梢钥聪耮it庫,歡迎大家提建議。
webpack 定義依賴目錄,在node環境下的解決方案
webpack依賴目錄 與 nodejs依賴目錄
webpack中配置resolve.alias依賴目錄,方便import
// build/webpack.base.config.js文件 alias: {'@scss': resolve('src/assets/scss'),'@api': resolve('src/api'),'@containers': resolve('src/containers'),'@components': resolve('src/components') },因此node下也需要配置一致的目錄,否則會提示"@components 目錄找不到"。這個可以通過 module-alias 進行配置。
// package.json 配置 "_moduleAliases": {"@scss": "src/assets/scss","@api": "src/api","@containers": "src/containers","@components": "src/components" }One More Thing
實踐過程中,踩到的一些坑點。
- node 需要支持ES6 modules,解決方案是 @babel/register
- 需要服務端渲染的組件,constructor和render不要寫類型window、document等瀏覽器特有的對象。
- Client端接口服務采用whatwg-fetch@2.0.4
- 這個案例中我沒有讓koa支持webpack配置,沒有支持在需要服務端渲染的組件import 樣式文件,用了另一種方式。
- 這個案例我未支持immutable.js,遇到了一些問題,還在處理。
- renderToString 服務端渲染組件只會觸發constructor和render和componentWillMount,不會觸發其他聲明周期,因此需要注意下。
- 別再componentWillMount里做數據獲取,記住,這很重要。
源碼github地址,如果剛好你有React-SSR的開發經驗,歡迎討論呀。
coocssweb/react-ssr?github.com大概效果如下:
目前簡單的實現了,首頁和詳情頁的功能。
總結
以上是生活随笔為你收集整理的react native text换行_基于React+Koa实现React SSR服务端渲染的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言switch制作菜单例题,c语言入
- 下一篇: 世界第一台电脑_2020世界计算机大会今