React之智能組件和木偶組件

智能組件 VS 木偶組件javascript

在 React + Redux 結合做爲前端框架的時候,提出了一個將組件分爲「智能」和「木偶」兩種css

  • 智能組件:它是數據的全部者,它擁有數據、且擁有操做數據的action,可是它不實現任何具體功能。它會將數據和操做action傳遞給子組件,讓子組件來完成UI或者功能。這就是智能組件,也就是項目中的各個頁面。
  • 木偶組件:它就是一個工具,不擁有任何數據、及操做數據的action,給它什麼數據它就顯示什麼數據,給它什麼方法,它就調用什麼方法,比較傻。這就是木偶組件,即項目中的各個組件。

所以,數據在page層獲取、數據的操做和處理在page層定義,組件就是傻傻的知道執行和顯示就好了,各操各的心。這種設計也整好符合目前不管是Vue、augular仍是React提倡的基於數據驅動的設計理念——程序定義好Model和View的關係,剩下的業餘處理只須要關心數據變化,View的變化由框架自動執行,無需像jquery時代再去手動操做DOM。html

數據管理前端

下面看一下數據在系統中是如何傳遞的。這裏的數據分爲兩種:java

  • 第一種能夠稱之爲「系統數據」,和業務無關的,通常任何系統中都會有。例如用戶id、用戶頭像、配置信息等,這個的特色就是符合單例模式,全局共用一套
  • 第二種能夠稱之爲「業務數據」,每一個頁面均可能不同。如在娛樂頻道須要的是娛樂新聞列表,而到了軍事頻道就須要軍事新聞的列表了,再到新聞詳情頁就須要新聞的內容了

針對這兩種不一樣的數據,固然要分開處理。針對第一種「系統數據」,系統一初始化就當即獲取,而後交給Redux作管理,這也符合Redux的特色。而針對第二種「業務數據」,那就何時用,就何時獲取。react


代碼架構(物理)jquery

使用React + Redux設計代碼結構,目前方式都比較統一,基本都是按照如下方式來設計,這些在github等社區都能找到類似的結構。git

app // 業務代碼目錄,或者叫 src --actions // 定義 Redux 的各個 action --components // 定義項目中的各個組件,裏面可能有不少個子文件夾 --config // 項目配置,無具體規定,自由發揮 --constants // 定義 Redux 中用到的各個常量 --container // 定義項目中的全部的頁面 --fetch // 定義項目中全部數據獲取、提交的方法 --reducers // 定義 Redux 的 reducer 規則 --router // 定義項目中的 router 規則 --store // 定義 Redux 的全局 store 對象 --util // 工具函數,例如時間格式的處理等 `--index.jsx // 入口,被 ../index.html 引用 resource // 靜態資源目錄,或者叫 static mocha // 測試用例,通常叫 test ,可是使用 fis3 時候 test 文件夾有其餘用處,不得不換個名字 .eslintignore .eslintrc.json .gitignore fis-conf.js index.html package.json README.md

以上目錄中,app/componentsapp/container是開發中修改最多的目錄。app/container裏面定義的都是頁面,即智能組件,只關心數據,功能比較單一,所以結構也比較簡單github

app/container list index.jsx Home.jsx Baijia.jsx detail detail.jsx imgDetail.jsx

可是針對組件app/components來講,要顯示樣式,固然就須要css和圖片,文件類型比較多。所以,要按照以下方式定義組件web

app/components LoadMore img icon.png index.jsx style.less BannerAd img close.png index.jsx style.less

即,用一個文件夾來表示單個組件,裏面的index.jsx是業務和模板代碼,style.less是樣式,img/文件夾放圖片文件。這樣的話,能夠把每一個組件都做爲一個總體來管理,並且引用的時候也比較方便,例如import LoadMore from '../../app/components/LoadMore'就能夠了——目錄名即組件的名字。


使用React重構百度新聞webapp前端  https://www.imooc.com/article/12433 

 ————————————————————————————————————————————————————————————————————————

 

Redux 的 React 綁定庫包含了 容器組件和展現組件相分離 的開發思想。明智的作法是隻在最頂層組件(如路由操做)裏使用 Redux。其他內部組件僅僅是展現性的,全部數據都經過 props 傳入。

那麼爲何須要容器組件和展現組件相分離呢?

這裏有個基本原則:容器組件僅僅作數據提取,而後渲染對應的子組件,記住這個點,Trust me!

看下面這個展現列表的例子,不區分容器和展現組件的狀況

// CommentList.js class CommentList extends React.Component { constructor() { super(); this.state = { comments: [] } } componentDidMount() { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render() { return <ul> {this.state.comments.map(renderComment)} </ul>; } renderComment({body, author}) { return <li>{body}—{author}</li>; } } 
  • 可用性:CommentList不能夠複用

  • 數據結構:組件應該對所須要的數據有所預期,但這裏其實沒有,PropTypes能夠很好的作到這一點

那麼來看下分離的狀況:

// CommentListContainer.js class CommentListContainer extends React.Component { constructor() { super(); this.state = { comments: [] } } componentDidMount() { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render() { return <CommentList comments={this.state.comments} />; } } // CommentList.js class CommentList extends React.Component { constructor(props) { super(props); } render() { return <ul> {this.props.comments.map(renderComment)} </ul>; } renderComment({body, author}) { return <li>{body}—{author}</li>; } } 

這樣就作到了數據提取和渲染分離,CommentList能夠複用,CommentList能夠設置PropTypes判斷數據的可用性

來看下容器組件和展現組件的區別:

展現組件 容器組件
關注事物的展現 關注事物如何工做
可能包含展現和容器組件,而且通常會有DOM標籤和css樣式 可能包含展現和容器組件,而且不會有DOM標籤和css樣式
經常容許經過this.props.children傳遞 提供數據和行爲給容器組件或者展現組件
對第三方沒有任何依賴,好比store 或者 flux action 調用flux action 而且提供他們的回調給展現組件
不要指定數據如何加載和變化 做爲數據源,一般採用較高階的組件,而不是本身寫,好比React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()
僅經過屬性獲取數據和回調  
不多有本身的狀態,即便有,也是本身的UI狀態  
除非他們須要的本身的狀態,生命週期,或性能優化纔會被寫爲功能組件  

優點:

  • 展現和容器更好的分離,更好的理解應用程序和UI

  • 重用性高,展現組件能夠用於多個不一樣的state數據源

  • 展現組件就是你的調色板,能夠把他們放到單獨的頁面,在不影響應用程序的狀況下,讓設計師調整UI

  • 迫使你分離標籤,達到更高的可用性

React 之容器組件和展現組件相分離解密  https://segmentfault.com/a/1190000006845396

 

————————————————————————————————————————————————————————————————————————

 

智能組件和木偶組件(也有叫容器組件和UI組件的)。見名知意,智能組件就要作一些比較智能比較‘高端’的工做,智能組件負責邏輯處理、數據獲取等比較‘智能’的工做; 
而木偶組件就比較‘呆板’,它原則上只負責展現功能,像一隻木偶,別人(智能組件)用線牽着它來控制它的展現內容。

來看一個例子:

class ListUI extends React.Component{ render(){ let data = this.props.data; return ( <ul> {data.map(item => <li key={item.id} >{item.text}</li>)} </ul> ) } } class List extends React.Component{ constructor(){ super(); this.getData = this.getData.bind(this); } render(){ let data = this.getData(); return <ListUI data={data} /> } getData(){ return [{id : 1,text : 'hello'},{id : 2,text : 'world'}]; } }

本例中組件List(智能組件)負責獲取數據(getData),實際開發中會比這複雜的多,涉及到調用接口獲取數據,數據的處理等等,本例側重說明概念,具體的就再也不贅述。 
而組件ListUI(木偶組件)則只負責數據的展現,傻瓜式的別人給他什麼他就展現什麼。

這是react開發中很重要的一個概念,這種解構分工明確,解構清晰,方便維護和擴展。實屬react開發必備之技能。

本例中還有一點值得注意: 
構造函數中的綁定this 實際開發中會在一個組件中定義不少方法,這些方法中可能會有回調函數,這就會致使this指向的問題(固然ES6中的箭頭函數能規避這個問題,也推薦只用ES6的寫法) 
可是也不排除有ES5的寫法存在,因此須要咱們綁定this,這裏強烈推薦在構造函數中統一的綁定this,這樣哪些方法綁定了this就一目瞭然也便於維護。

基於這個概念作一些擴展。 
事件處理: 有了以上概念的基礎,現給組件添加一個點擊事件,目的是點擊li時彈出當前li的文本內容。根據以上的概念,要把邏輯處理的方法寫在智能組件中,而後把方法做爲一個prop傳遞給木偶組件,最後在木偶組件中添加點擊事件來調用傳過來的方法。 
代碼以下:

class ListUI extends React.Component{ constructor(){ super(); this.clickHandler = this.clickHandler.bind(this); } render(){ let data = this.props.data; return ( <ul> {data.map(item => <li key={item.id} onClick={this.clickHandler}>{item.text}</li>)} </ul> ) } clickHandler(e){ this.props.clickHandler(e); } } class List extends React.Component{ constructor(){ super(); this.getData = this.getData.bind(this); this.clickHandler = this.clickHandler.bind(this); } render(){ let data = this.getData(); return <ListUI data={data} click={this.clickHandler}/> } getData(){ return [{id : 1,text : 'hello'},{id : 2,text : 'world'}]; } clickHandler(e){ let ele = e.currentTarget || e.srcElement; alert(ele.innerHTML); } }

最後想說的是:智能組件和木偶組件這種編程思想很是重要,開發大型項目時體現的尤其明顯,當項目很大時更須要把木偶組件細分,否則代碼會雜亂無章,很是的不便於閱讀,及其的不利於維護和擴展,最後的結果是項目沒法進行。

摘自: https://blog.csdn.net/hkwBest/article/details/78688205?locationNum=6&fps=1 

相關文章
相關標籤/搜索