因爲近期在涉及到封裝組件的時候遇到了一些問題,因而我認真地瞭解了一下react封裝組件過程當中應該要涉及和思考到的一些問題,寫了下來。(如下主要是針對UI組件,因爲水平有限不保證內容正確性,僅僅是一些我的的思考)css
組件能夠將UI切分紅一些的獨立的、可複用的部件,這樣就只需專一於構建每個單獨的部件。node
所謂組件,即封裝起來的具備獨立功能的UI部件。react
在 React 中,一切皆是組件,所以理解組件的工做流與核心尤其重要。es6
且react中有多種建立組件的方式和各類各樣的組件概念,所以在設計組件的時候應該使用哪一種組件的建立方式且應該設計一個怎樣的組件都值得深刻思考。數組
咱們常常談一個設計良好的系統應該是高內聚低耦合的,那麼其實我認爲一個好的組件也應該是具備高內聚低耦合的特性。bash
由於低耦合會帶來如下的好處:異步
而高耦合的組件間會很容易出現一個問題,
就是沒法或者很艱難去修改一個大量依賴其餘組件的組件,
甚至只是改一個用來傳遞數據的字段都會致使大量的修改。函數
一個封裝良好的組件應該是要隱藏其內部結構的,並經過一組 props來提供控制其行爲的途徑。性能
隱藏內部結構是必須的。內部結構或實現細節不該該能被其餘組件知道或關聯。測試
React 組件能夠是函數式的,也能夠是基於類的,能夠定義實例方法、設置 refs、維護 state或是使用生命週期方法。而這些實現細節被封裝在組件自身中,其餘組件不該該窺見其中的任何細節。
基於此特色來設計的組件對其餘組件的依賴是極低的,帶來的是低耦合的特色和好處。
我認爲組件應該要符合單一職責原則,
一個組件應該儘可能只負責一件事情,而且把這件事情作好,
由於我以爲一個組件若是負責處理的事情過多,
在修改其中一件事情的時候頗有可能也會影響到它負責的其餘事情,且不利於維護和複用。
在設計一個組件的時候咱們不該該僅限於實現當前的需求,
設計出一個只適用於單一項目的組件,而是應該是一個能夠適應大部分同種需求的通用組件。
因此咱們在碰到一個需求的時候應該首先對需求進行抽象,而不是看到設計稿就擼着袖子上。
例如碰到一個輪播圖組件的需求的時候,咱們拆分如下這個需求,能夠獲得:
一個好的組件應該是要像存在魔法同樣,只須要極其少數的參數和條件就能夠獲得指望的效果。就像這個輪播圖組件同樣,組件應該至少知道的信息有:
其餘能夠知道也能夠不知道的信息能夠有:
是否開啓自動輪播,默認是開啓或者不開啓
圖片滾動是左右仍是上下,默認是左右
等等 ....................................
(3)這個組件會反饋什麼
一個可用的輪播圖效果
父組件向封裝好的子組件通訊一般是經過props
做爲組件的輸入,props的值應該最好是js基本類型 (如 string、number、boolean)
可是props能夠傳入的不只僅只是這些,它但是一個神奇的東西,它能夠傳入包括:
<Message text="Hello world!" modal={false} />;
複製代碼
<Message
data={{
thexAxis: thexAxis ,
lineData : lineData
}}
/>
複製代碼
<MoviesList items={['Batman Begins', 'Blade Runner']} />
複製代碼
<Message type="text" onChange={handleChange} />
複製代碼
function If({ Component, condition }) {
return condition ? <Component /> : null;
}
<If condition={false} component={LazyComponent} />
複製代碼
爲避免破壞封裝,要謹慎對待 props 傳遞的細節。
父組件對子組件設置 props 時,也不該該暴露自身的結構。
好比,把整個組件實例或 refs 當成 props 傳遞之類的神奇操做。
訪問全局變量是另外一個對封裝形成負面影響的問題。
咱們能夠經過 proptypes來對傳入的數據進行類型限制。
react建立組件有三種方法,分別是:
而目前react推薦ES5方式和ES6方式建立組件的寫法中推薦的是ES6的寫法,因此這裏就不對ES5的寫法進行討論了。
React.Component是以ES6的形式來建立React組件,也是如今React官方推薦的建立組件的方式,
其和React.createClass建立的組件同樣,也是建立有狀態的組件。
相比React.createClass方式,React.Component帶來了諸多語法上的改進
ES6使用import方式替代ES5的require方式來導入模塊,其中import { }能夠直接從模塊中導入變量名,此種寫法更加簡潔直觀。
在ES6的語法規則中,React的組件使用的類繼承的方式來實現,去掉了ES5的getInitialState的hook函數,state的初始化則放在constructor構造函數中聲明。
React把組件當作一個狀態機。經過與用戶的交互,實現不一樣狀態,而後渲染UI,讓用戶界面和數據保持一致。 組件的任何UI改變,均可以從State的變化中反映出來; State中的全部狀態都用於反映UI的變化,不該有多餘狀態。
React內部是經過調用組件的定義來獲取被渲染的節點,而對於不一樣的組件定義方式,其獲取節點的步驟也不同。以下:
//function方式定義
function Example() {
return <div>this is a div</div>;
}
const node = Example(props);
// 類方式定義
class Example extends React.Component {
render() {
return <div>this is a div</div>;
}
}
const instance = new Example(props);
const node = instance.render();
複製代碼
在這裏,函數直接調用,類則須要先實例化再去調用實例化對象上的render方法;
若是將類按照普通函數去調用則會報錯
由於這方面沒有詳細去了解過,因此也只是粗淺總結一下其區別:
PureComponent除了提供了一個具備淺比較的shouldComponentUpdate方法,
PureComponent和Component基本上徹底相同。
當組件更新時,若是組件的 props 和 state 都沒發生改變, render 方法就不會觸發,省去 Virtual DOM 的生成和比對過程,達到提高性能的目的。
若是咱們想用PureComponent去代替Component的時候不須要去作太多的事情,
僅僅是把Component改爲PureComponent便可。 可是咱們並不是能夠在全部地方都用PureComponent去代替Component,
具體仍是要按照實際狀況來選擇,由於瞭解不深就不在此處詳談了。
無狀態組件更多的是用來定義模板,接收來自父組件props傳遞過來的數據,
使用{props.xxx}的表達式把props塞到模板裏面。
無狀態組件應該保持模板的純粹性,以便於組件複用,因此一般UI組件應該是無狀態組件。
相似於:
var Header = (props) = (
<div>{props.xxx}</div>
);
複製代碼
而有狀態組件一般是用來處理定義交互邏輯和業務數據
(使用{this.state.xxx}的表達式把業務數據掛載到容器組件的實例上(有狀態組件也能夠叫作容器組件,無狀態組件也能夠叫作展現組件),
而後傳遞props到展現組件,展現組件接收到props,把props塞到模板裏面。
相似於:
class Home extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<Header/>
)
}
}
複製代碼
高階組件給個人感受相似於高階函數,都是接受一個東西的輸入, 而後再給輸入的東西添加新的特性做爲一個新的東西輸出, 看起來相似於裝飾器模式的實現。 可是由於目前爲止沒有寫太高階組件,因此就不在這裏討論了。