react服務端/客戶端,同構代碼心得

FKP-REST是一套全棧javascript框架

react服務端/客戶端,同構代碼心得

做者:webkixi

react服務端/客戶端,同構代碼心得javascript

服務端,客戶端同構一套代碼,大前端的夢想,爲了省略重複的代碼,卻平添了很多煩惱,頭髮也白了,。。。。,妹子還在家等我.css

目錄結構問題

咱們引用了不少的庫,在開發前端代碼的時候,習慣性的咱們不會考慮到node端對於庫的引用,這就是開始同構最大的痛點。整個目錄結構須要調整。html

減小調用層級

好比說開發前端時,有一個libs的庫,在react的前端組件開發時,咱們屢次調用到libs裏面的若干方法,這個時候,爲了同構,須要將libs庫作一個抽離,既是從前端代碼中抽離到中間的部分。前端

這麼說有點很差理解,簡單配一個圖吧。java

FKP原來的結構node

node -> fed -> libs -> component -> pagesreact

大體上咱們原來的結構都相似於這樣,調整好以後的結構,以下:webpack

node <-> libs <-> fed -> component -> pagesgit

這樣,咱們將libs抽離到中間的部分,相對來講,在同構時,require的層級少了不少。可是還不夠,爲了 將react同構,咱們還須要調整component的結構,以下:github

node <-> libs <-> component <-> fed -> pages

如此這般,大體的結構算調整好了,接下來解決require的坑,讓webpack和node端require作到無縫切換。 讓require('libs/index'),這種引用兼容於兩端。 在這裏FKPJS用到了一個好用的包文件app-module-path,指定node端require的目錄優先級,及自寫了一個 include的方法(封裝require),來簡化require的調用深度。 並對libs庫作更細化的抽象與提取,最後,FKPJS的libs結構作到如上所述。

組件結構問題

解決了目錄結構問題後,爲了作到同構,咱們須要合理的組件結構,以方便兩端的調用,通過本人的實踐,FKPJS將組件分爲三層,原子組件組合組件組件封裝,以下圖

原子 -> 組合 -> 封裝

1. 原子組件(react/widgets)

適用node/fed,複用型組件,最小粒度化,產出純結構,純粹的react組件,封裝了對數據的處理

2. 組合組件(react/modules/xxx/_component/xxx)

適用node/fed,組合不一樣的原子組件,並引入相關mixins,實現like redux,產出純結構,純react組件,傳輸數據

3. 組件封裝(react/modules/xxx/yyy)

適用於前端,最表層,處理配置文件,可導入JQ等庫實現內部邏輯、效果,並響應由業務層傳導進來的方法,數據等等。

在FKPJS中封裝的比較好的有兩個組件,react/modules/pagination/pagireact/modules/list/base_list.jsx,list組件有點複雜,咱們先說下 pagi這個組件吧

pagi這個組件,用於分頁,可先後端同構

Demo

前端業務中實現的代碼

varPagi=require('modules/pagination/pagi'),// 初始化分頁數據 pageData ={ total:60, per:20, url:'/', query:'page='}Pagi(pageData,{ container:'pagi',begin:{ start:0, off:5}, itemMethod: bindItem })

服務端同構的代碼

// pages/pagi.jsvar _props ={ itemMethod:false, listMethod:false, itemClass:'', listClass:'pagenation wid-12', data:{ total:60, per:20, url:'/', query:'page='},begin:{ start:0, off:5}}var reactHtml =yield react2html('react/modules/pagination/pagi', _props) reactHtml[0]='<div class="pagi" id="pagi" >'+reactHtml[0]+'</div>' oridata.pagi = reactHtml[0]return.....

組件封裝

封裝部分

// 封裝方法function pagination(data, opts ){// 處理配置文件 var noop =false, dft ={ container:'', globalName:'_Pagi', itemMethod: noop, listMethod: noop, itemClass:'', listClass:'pagenation wid-12', data:{ total:200, per:10, url:'/', query:'page='},begin:{ start:0, off:7}} dft = _.assign(dft, opts)if(!dft.container)returnfalse;if(data){ dft.data = data }// fkp redux// 初始化組件數據// FKPJS使用SA代替redux// 須要在組合組件中引入,store的minxin SA.set(dft.globalName,{ data: data,begin: dft.begin})// fkp redux // 將組建的action放到 SA 的全局名字中// 須要在 _Pagi組件中引入 store 這個mixinsvarPagi=_Pagi(dft.globalName)// 渲染組件 render(<Pagi data={data}begin={dft.begin} itemDefaultMethod={idm} itemMethod={dft.itemMethod} listMethod={dft.listMethod} itemClass={dft.itemClass} listClass={dft.listClass}/>, document.getElementById(dft.container))}// 服務端同構,執行這個部分 pagination.server =function(){return_Pagi(true)};module.exports = pagination

組合組件

這裏不貼出全部代碼,部分

varList=require('../../../widgets/listView/list');varStore=require('../../../mixins/store');//引入這個就完成了reduxvar _storeName;var _jump =false;// List的item組件varPageItem=React.createClass({ componentDidMount:function(){var ele =React.findDOMNode(this), mtd =this.props.itemMethod, dmtd =this.props.itemDefaultMethod;if(dmtd &&typeof dmtd==='function'){ dmtd.call(ele, _storeName, mtd);}},.......

組合組件-算法部分

render:function(){if(this.state.data){var data =this.state.data, newData =[], pages = data.total/data.per, pre, aft, half,begin=this.state.begin,........

組合組件-實現部分

function actRct( storeName ){// 根據storeName,能夠實現多個組件,並redux化// for serverif(storeName===true){returnReact.createClass( pagenation );}// for client _storeName = storeName||'_Pagi';var _rct = _.cloneDeep(pagenation);if( _rct.mixins && _rct.mixins.length ){ _rct.mixins.push(Store( _storeName ))//實現redux}else{ _rct.mixins =[Store( _storeName )]}returnReact.createClass( _rct );//返回react組件

原子組件

  1. List List source
  2. Item Item source
  3. Item 算法部分 Item算法實現

綜上所述,作到兩端同構的話,須要有一個全局的眼光,從基礎的目錄結構開始,到組件的結構,其實還有css的結構,html的結構,這裏就不一一說明了,但願能拋磚引玉

文章目錄

    • 目錄結構問題
    • 組件結構問題
相關文章
相關標籤/搜索