首先作為一個合格的開發者,不要只滿足於編寫出了可以運行的代碼,而耍了解代碼背 后的工作原理;不要只滿足於自己編寫的程序能夠運行,還要讓自己的代碼可讀而且易 於維護 。 這樣才能開發出高質量的軟件 。
易於維護組件的設計要素
作為軟件設計的通則,組件的划分要滿足高內聚(High Cohesion)和低耦合(Low Coupling)的原則 。
高內聚指的是把邏輯緊密相關的內容放在一個組件中 。 用戶界面無外乎內容 、 交互 行為和樣式 。 傳統上,內容由 HTML 表示,交互行放在 JavaScript代碼文件中,樣式放 在 css 文件中定義 。 這雖然滿足一個功能模塊的需要,卻要放在三個不同的文件中,這 其實不滿足高內聚的原則 。 React卻不是這樣,展示內容的 JSX、定義行為的 JavaScript 代碼,甚至定義樣式的 css,都可以放在一個 JavaScript文件中,因為它們本來就是為了實現一個目的而存在的,所以說 React天生具有高內聚的特點 。
低耦合指的是不同組件之間的依賴關系要盡量弱化,也就是每個組件要盡量獨立 。保持整個系統的低耦合度,需要對系統中的功能有充分的認識,然后根據功能點划分模 塊,讓不同的組件去實現不同的功能,這個功夫還在開發者身上,不過, React 組件的對 外接口非常規范,方便開發者設計低禍合的系統 。
react組件的數據
俗話說的好 差勁的程序員操心代碼,優秀的程序員操心數據結構和它們之間的關系
React組件的數據分為兩種, prop和 state,無論 prop或者 state 的改變,都可能引發組件的重新渲染,那么,設計一個組件的時候,什么時候選擇用 prop什么時候選擇用state 呢?其實原則很簡單, prop 是組件的對外接口, state 是組件的內部狀態,對外用prop,內部用 state。
React 的 prop
在 React 中, prop ( property 的簡寫)是從外部傳遞給組件的數據, 一個 React 組件 通過定義自己能夠接受的 prop 就定義了自己的對外公共接口 。
每個 React組件都是獨立存在的模塊,組件之外的一切都是外部世界,外部世界就是通過 prop 來和組件對話的 。
我們先從外部世界來看, prop是如何使用的,在下面的JSX代碼片段中,就使用了prop:
<SampleButton borderWidth={2} onClick={onButtonClick} style={{ color: "red" }} />
在上面的例子中,創建了名為 SampleButton 的組件實例,使用了名字分別為 borderWidth、 onClick 和 style 的 prop,看起來, React 組件的 prop 很像是 HTML 元素的屬性, 不過, HTML 組件屬性的值都是字符串類型,即使是內嵌 JavaScript,也依然是字符串形 式表示代碼。 React組件的 prop所能支持的類型則豐富得多,除了字符串,可以是任何 一種 JavaScript語言支持的數據類型。
比如在上面的 SampleButton 中, borderWidth 就是數字類型, onClick是函數類型, style 的值是一個包含 color字段的對象,當 prop 的類型不是字符串類型時,在 JSX 中必 須用花括號{}把 prop 值包住,所以 style 的值有兩層花括號,外層花括號代表是 JSX 的 語法,內層的花括號代表這是一個對象常量。
當外部世界要傳遞一些數據給 React組件,一個最直接的方式就是通過 prop ;同樣,React組件要反饋數據給外部世界,也可以用 prop,因為 prop 的類型不限於純數據,也 可以是函數,函數類型的 prop等於讓父組件交給了子組件一個回調函數,子組件在恰當 的實際調用函數類型的 prop,可以帶上必要的參數,這樣就可以反過來把信息傳遞給外 部世界.
看下面代碼
class ControlPanel extends Component { render () { return ( <div> <Counter caption=”First” initValue={O} /> <Counter caption=” Second" initV alue={lO} /> <Counter caption=”Third” initValue={20} /> </div> ); ) )
對於 Counter 組件,父組件 Contro!Panel 就是外部世界,我們看 Contro!Panel 是如何 用 prop 傳遞信息給 Counter 的,
Contro!Panel組件包含三個 Counter組件實例 在 ControlPanel 的 render 函數中將這 三個子組件實例用 div包起來,因為 React要求 render函數只能返回一個元素。
在每個 Counter組件實例中,都使用了 caption 和 initValue兩個 prop。 通過名為 ca嚴ion 的 prop, ControlPanel傳遞給 Counter組件實例說明文字。 通過名為 initValue 的 prop傳遞給 Counter組件一個初始的計數值 。
讀取 prop值
我們再來看 Counter組件內部是如何接收傳人的 prop 的,首先是構造函數,代碼 如下:
class Counter extends Component { constructor(props) { super (props) ; th工s.onClickincrementButton = this.onClickincrementButton.bind(this); this.onClickDecrementButton = this.onClickDecrementButton.bind(this); this.state= { count: props.initV alue I I 0 } }
如果一個組件需要定義自己的構造函數,一定要記得在構造函數的第一行通過 super 調用父類也就是 React.Component 的構造函數 。 如果在構造函數中沒有調用 super(props), 那么組件實例被構造之后,類實例的所有成員函數就無法通過 this.props訪問到父組件傳 遞過來的 props值。很明顯,給 this.props賦值是 React.Component構造函數的工作之一。
在 Counter 的構造函數中還給兩個成員函數綁定了當前 this 的執行環境,因為 ES6 方法創造的 React組件類並不自動給我們綁定 this到當前實例對象。
在構造函數的最后,我們可以看到讀取傳入 prop 的方法,在構造函數中可以通過參 數 props 獲得傳人 prop 值,在其他函數中則可以通過 this.props 訪問傳人 prop 的值,比如在 Counter 組件的 render 函數中,我們就是通過 this.props 獲得傳人的 caption, 函數代碼如下:
const{ caption }=this.props
在上面的代碼中,我們使用了 ES6 的解構賦值( destructuring assignment)語法從 this. props 中獲得了名為 caption 的 prop 值 。
propTypes檢查
在 ES6 方法定義的組件類中,可以通過增加類的 propTypes 屬性來定義 prop 規格, 這不只是聲明,而且是一種限制,在運行時和靜態代碼檢查時,都可以根據 propTypes 判斷外部世界是否正確地使用了組件的屬性 。
比如,對於 Counter組件的 propTypes定義代碼如下:
其中要求 caption必須是 string類型, initValue必須是 number類型 。 可以看到,兩 者除了類型不同之外,還有一個區別: caption 帶上了 isRequried,這表示使用 Counter 組件必須要指定 caption;而 initValue 因為沒有 isRequired,則表示如果沒有也沒關系 。
為了驗證 propTypes 的作用,可以嘗試故意違反 propTypes 的規定使用 Counter實 例,