【譯】函數式的React

原文: 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

使用 render() 渲染輸出

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 的不變性

如你所知,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" 不相符,因此我改了例子中傳遞的文案,嘿嘿嘿...

組合 vs 繼承

在面向對象的編程範例中,對於類,很容易將繼承視爲一種標準。 可是,若是從函數的角度考慮 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 的做者。

本文已經聯繫原文做者,並受權翻譯,轉載請保留原文連接

相關文章
相關標籤/搜索