react 是現在最流行的 JavaScript 庫之一。使用 react 可以非常輕松地創建 Web 用戶交互界面。 它的成功有很多因素,但也許其中一個因素是清晰有效的編程方法。
在 React 的世界中,UI 是由一個一個組件所組成的。組件可以組合在一起以創建其他組件, 應用本身就是一個包含了所有組件的一個大組件。開發者使用 React 會很容易聯想到:面向對象編程 。因為定義組件的語法本身,就會給人這種感覺:
class HelloReact extends Component { render() { return (<div>Hello React!</div>); } }
然鵝,在面向對象的的表象之下,React 隱藏了一種函數式的特質。讓我們看看這些特質都是什么?
使用 render() 渲染輸出
React 組件的一大特征是是包含了 render() 方法。沒有包含 render() 方法的組件不是 React 組件。render() 方法總會返回一個 React 元素,這種行為就像是組件的一種特征一樣。換句話說,React 會要求任何組件必須有輸出。組件是根據輸入來返回輸出的,這樣來考慮組件的話,就會讓你感覺組件更像一個函數,而不是一個對象。
組件就是一個函數
實際上,您不僅可以將 React 組件視為函數。 您還可以用函數來實現組件。 以下代碼展示了如何使用函數實現上面定義的組件:
const HelloReact = () => <div>Hello React!</div>;
如您所見,它是一種實現組件的簡單而緊湊的方法。
此外,您可以將參數傳遞給函數:
const Hello = (props) => <div>Hello {props.name}!</div>;
在上面的示例中,您傳遞了 props 參數,這里的 props 對象用於將數據從一個組件傳遞到另一個組件。
props 的不變性
如你所知,props 是不可改變的,你可以閱讀他們,但你無法改變它們。這也正是 React 組件的函數特性之一。props 是組件的輸入參數,因此給予其不可變性可以避免副作用。實際上,這也是函數式編程的基本原則之一:函數不能更改輸入參數。
譯注:純函數的介紹,推薦看下這個 - 函數式編程 - 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 元素。
廣州品牌設計公司https://www.houdianzi.com PPT模板下載大全https://redbox.wode007.com
組件和狀態
應用程序的狀態是隨時間變化的數據集。 函數式編程范例旨在避免在應用程序中使用狀態。 實際上,應用程序狀態管理是軟件開發中復雜性的主要來源之一。 但是,由於你不能沒有它,至少你應該嘗試限制它的使用並使其更易於管理。
React 的開發指南促進了無狀態組件的創建,即無 state 組件。 這種組件的輸出僅僅取決於傳入的 props。 無狀態組件看起來很像純函數,實際上也是如此。
但是,如您所知,在不使用 state 的情況下無法編寫復雜的應用程序。 訣竅是在應用程序的幾個點上隔離 state ,如果在一個點上更好。 此策略會要求開發人員在根組件中使用狀態提升。 換句話說,應該在上層節點中保留狀態,而其后代應該是無狀態組件。 這樣,我們可以更好地控制狀態,因為它只由單個根組件管理。
結論
對於剛開始使用 React 的開發者來說,React 並不是像看起來那樣,它更加適合函數式編碼的原則,而不是面向對象的原則。通常,這允許開發者編寫更加正式可驗證的代碼,例如使用自動化測試來測試應用程序。 我建議充分利用 React 的函數特性來編寫更易於維護的代碼。