本文我們將主要討論如何使用高階組件的方式取代傳統的React Mixins。
Statement
作者:景莊,Web開發者,主要關注JavaScript、Node.js、React、Docker等。
源碼:本文的源代碼地址:https://github.com/wwsun/react-es6-tutorial
介紹
當使用React.createClass()的時候,你可能會使用到所謂的Mixins。使用Mixins允許我們在我們的React組件中混入一些附加的功能。 這個概念并不是React所獨有的,它也存在于普通的JS或其他語言的框架中。
如果是要使用ES6來編寫React組件的話,我們將不建議你使用React的mixin機制了。 本文并不會深入的探討為什么不建議使用mixin的原因。如果你感興趣的話,你可以通過如下的鏈接查看相關的資料:
下面我們將主要關注的是具體的例子。
使用高階組件替代Mixins
本文我們將繼續使用之前的代碼,并對代碼做一定的修改。通過本文,我們將能夠在頁面中顯示用戶在當前頁面停留的時間。
為什么能夠更好的進行說明,我們將不會修改CartItem組件的代碼。而是通過提供一些能夠包裹CartItem組件的組件, 并通過一些額外的功能來“增強”CartItem組件。這樣的組件我們稱之為高階組件(Higher-Order Component)。
這個概念聽起來可能有點含義模糊,隨著我們的深入,你將會理解的更透徹一點。
假設,我們有一個IntervalEnhance組件,我們在CartItem組件中導入它,并通過它來包裹原有的導出對象。
// src/components/cart-item.jsximportReactfrom'react';import{IntervalEnhance}from"./interval-enhance.jsx";// 1. 導入包裹組件classCartItemextendsReact.Component{// component code here}exportdefaultIntervalEnhance(CartItem);// 2. 包裹原有的CartItem組件
現在我們將來編寫這個IntervalEnhance組件。
// src/components/interval-enhance.jsximportReactfrom'react';// 1exportletIntervalEnhance=ComponsedComponent=>classextendsReact.Component{constructor(props){super(props);this.state={seconds:0// 2};}// 3componentDidMount(){this.interval=setInterval(this.tick.bind(this),1000);}// 3componentWillUnmount(){clearInterval(this.interval);}tick(){this.setState({seconds:this.state.seconds+1000});}render(){// 4return;}};
我們一一的來解釋上面幾處加注釋的代碼:
ComposedComponent => class extends React.Component- 這其實和定義返回類的函數一樣。 其中ComposedComponent是我們想要“增強”的組件(在上面的代碼中就是CartItem組件)。 通過使用export let IntervalEnhance我們可以導出整個函數為IntervalEnhance(也就是上面代碼中的CartItem)。 所以,上面的代碼也可以這么寫:
javascript let IntervalEnhance = function (ComposedComponent) { return class extends React.Component { // class methods here }; };
初始化組件的狀態(state),設置seconds的值為0。
組件的生命周期鉤子函數,用于期待能夠和暫停計數器。
最重要的一個部分。這行代碼將所有的state或props拿到我們的“增強器”組件中,然后轉移到CartItem組件中。 通過這種方式,CartItem組件將能夠訪問到this.state.seconds屬性。
最后一步是改變CartItem組件中的render方法。我們將直接向視圖中輸出this.state.seconds:
importReactfrom'react';import{IntervalEnhance}from"./interval-enhance.jsx";classCartItemextendsReact.Component{// component code hererender(){returnTimeelapsedforinterval:{this.props.seconds}ms;}}exportdefaultIntervalEnhance(CartItem);
現在我們可以瀏覽器中檢查結果了,我們將在頁面中看到一行文字,顯示用戶在當前頁面停留的時間。
注意:所有這一切并沒有改變CartItem組件的任何主體代碼(除了render方法)! 這就是為什么高階組件這么強大的原因!
裝飾器*
此外,ECMAScript的未來標準中還將引入裝飾器的概念,通過這種方法能夠更優雅的解決Mixin的問題, 本文不對未標準化的特性做過多的介紹。不過,代碼大致如下:
importReactfrom'react';import{IntervalEnhance}from"./interval-enhance";@IntervalEnhanceexportdefaultclassCartItemextendsReact.Component{// component code here}
PureRenderMixin呢?
如果你使用了諸如PureRenderMixin這樣的mixins,那么醬油一些其他的方法來使用ES6將這種功能帶到React組件中。 其中一種如下:
classFooextendsReact.Component{constructor(props){super(props);this.shouldComponentUpdate=React.addons.PureRenderMixin.shouldComponentUpdate.bind(this);}render(){return
Helllo
}}
小結
高階組件非常的強大并且表達能力強。目前,它們使用非常廣泛,并且可以作為古老的mixin語言的替代。
對于高階組件的使用最出名的要屬Relay框架。Relay是Facebook發布的一個完全的基于React的框架。 你所編寫的沒一個組件都可以被包裹進Relay容器,它能夠自動檢索數據依賴,以及一些其他的事。 這非常的便捷,并且在你剛接觸的時候會覺得很神奇。
References
About mixins in ES6 in official React blog