原文: The functional side of React
做者:Andrea Chiarelli
譯者:博軒
React 是如今最流行的 JavaScript 庫之一。使用 React 能夠很是輕鬆地建立 Web 用戶交互界面。 它的成功有不少因素,但也許其中一個因素是清晰有效的編程方法。javascript
在 React 的世界中,UI 是由一個一個組件所組成的。組件能夠組合在一塊兒以建立其餘組件, 應用自己就是一個包含了全部組件的一個大組件。開發者使用 React 會很容易聯想到:面向對象編程 。由於定義組件的語法自己,就會給人這種感受:html
class HelloReact extends Component {
render() {
return (<div>Hello React!</div>);
}
}複製代碼
然鵝,在面向對象的的表象之下,React 隱藏了一種函數式的特質。讓咱們看看這些特質都是什麼?java
React 組件的一大特徵是是包含了 render()
方法。沒有包含 render()
方法的組件不是 React 組件。render()
方法總會返回一個 React 元素,這種行爲就像是組件的一種特徵同樣。換句話說,React 會要求任何組件必須有輸出。組件是根據輸入來返回輸出的,這樣來考慮組件的話,就會讓你感受組件更像一個函數,而不是一個對象。react
實際上,您不只能夠將 React 組件視爲函數。 您還能夠用函數來實現組件。 如下代碼展現瞭如何使用函數實現上面定義的組件:typescript
const HelloReact = () => <div>Hello React!</div>;複製代碼
如您所見,它是一種實現組件的簡單而緊湊的方法。編程
此外,您能夠將參數傳遞給函數:segmentfault
const Hello = (props) => <div>Hello {props.name}!</div>;複製代碼
在上面的示例中,您傳遞了 props
參數,這裏的 props
對象用於將數據從一個組件傳遞到另外一個組件。app
如你所知,props
是不可改變的,你能夠閱讀他們,但你沒法改變它們。這也正是 React
組件的函數特性之一。props
是組件的輸入參數,所以給予其不可變性能夠避免反作用。實際上,這也是函數式編程的基本原則之一:函數不能更改輸入參數。ide
譯註:純函數的介紹,推薦看下這個 - 函數式編程 - wiki,以及我以前翻譯過的 【譯】JavaScript 中的函數式編程原理
關於 React
,它的另外一個特性就是單項數據流。這意味着在組件的層次結構中,數據必須從較高的組件流向較低的組件,反之亦然。若是咱們將組件視爲對象,這個觀點就會顯得有些牽強。相反,若是咱們從函數的角度去考慮組件,就會顯得很天然。函數式編程
考慮一下下面的代碼:
class App extends Component {
render() {
return (<Hello name="React" />)
};
}
class Hello extends Component {
render() {
return (<div>Hello {props.name}!</div>);
}
}複製代碼
例子中有兩個組件:App
組件使用 Hello
組件來展現 「Hello React!」 。同時,例子中也隱式的定義了組件之間的層次結構。可是乍一看,沒法經過 name
屬性來來看清楚數據的流向。
如今,讓咱們來看看使用函數修改以後的代碼:
const App = () => <Hello name="React" />;
const Hello = (props) => <div>Hello {props.name}!</div>;複製代碼
經過上面組件的層級結構能夠清楚的看出,不過是 App()
和 Hello()
,兩個函數的組合。你也能夠將其視爲下面的內容:
const App = () => Hello("React");複製代碼
從上面的例子中就能夠很明顯的看出,「React」 文本是怎樣在 App 組件中傳遞的了。
譯註:這裏原文例子中使用的是
const App = () => Hello("John");
,和文章中的 "React" 不相符,因此我改了例子中傳遞的文案,嘿嘿嘿...
在面向對象的編程範例中,對於類,很容易將繼承視爲一種標準。 可是,若是從函數的角度考慮 React
組件,繼承就會顯得不那麼天然。
例如,假設您要升級 Hello
組件,以便它還能夠顯示 「歡迎消息」 。 您能夠將其與 Hello
組件組合來建立新組件,好比下面的例子:
const HelloAndWelcome = (props) => <div><Hello {…props} /><p>Welcome to React!</p></div>;複製代碼
正如Facebook團隊所宣稱的那樣,真的不多須要繼承。
高階組件是 React
編程中的常見模式。 它容許重用組件邏輯來建立新組件。 簡單來講,高階組件是一個函數,它將一個組件做爲輸入並返回一個新組件做爲其輸出。 如下是高階組件的示例:
const AddWelcome = (GreetingComponent) => {
class TheNewComponent extends Component {
render() {
return (
<div>
<GreetingComponent {…this.props}/>
<p>Welcome to React!</p>
</div>);
}
}
return TheNewComponent;
};複製代碼
函數 AddWelcome()
接受 GreetingComponent
參數,並在新組件 TheNewComponent
定義的 render()
方法中使用它。 這個新組件只是在 GreetingComponent
的輸出後添加一條歡迎消息。 最後,函數 AddWelcome()
會返回新組件。
您可使用此功能,如如下示例所示:
const HelloAndWelcome = AddWelcome(Hello);複製代碼
經過使用 AddWelcome()
包裝 Hello
組件,您將得到一個新組件。
您能夠將上面例子中的高階函數 AddWelcome()
用函數的方式來從新整理:
const AddWelcome = (GreetingComponent) => {
const TheNewComponent = (props) => <div><GreetingComponent {…props}/><p>Welcome to React!</p></div>;
return TheNewComponent;
};複製代碼
如你所見,這就像是一個高階函數,這個函數接受一個函數,返回一個新的 React
元素。
應用程序的狀態是隨時間變化的數據集。 函數式編程範例旨在避免在應用程序中使用狀態。 實際上,應用程序狀態管理是軟件開發中複雜性的主要來源之一。 可是,因爲你不能沒有它,至少你應該嘗試限制它的使用並使其更易於管理。
React
的開發指南促進了無狀態組件的建立,即無 state
組件。 這種組件的輸出僅僅取決於傳入的 props
。 無狀態組件看起來很像純函數,實際上也是如此。
可是,如您所知,在不使用 state
的狀況下沒法編寫複雜的應用程序。 訣竅是在應用程序的幾個點上隔離 state
,若是在一個點上更好。 此策略會要求開發人員在根組件中使用狀態提高。 換句話說,應該在上層節點中保留狀態,而其後代應該是無狀態組件。 這樣,咱們能夠更好地控制狀態,由於它只由單個根組件管理。
對於剛開始使用 React
的開發者來講,React
並非像看起來那樣,它更加適合函數式編碼的原則,而不是面向對象的原則。一般,這容許開發者編寫更加正式可驗證的代碼,例如使用自動化測試來測試應用程序。 我建議充分利用 React
的函數特性來編寫更易於維護的代碼。
Andrea Chiarelli 是 Beginning React 的做者。本文已經聯繫原文做者,並受權翻譯,轉載請保留原文連接