React與ES6(四)ES6如何處理React mixins
在使用React.createClass()
的時候你也許使用過一個所謂的mixin
的東西。使用它,你可以給React元件天劍很多其他的功能。這個概念不止用在React上,也用在很多其他的程式語言或者框架上。
在ES6中不能夠在使用React的mixin機制。本文不會糾結於原因為何。我們只關注ES6中的替代方法。
High-Order Component
或者可以叫做高階元件。
我們使用前文中使用的CartItem
元件作為例子,在其中顯示一個每秒計數增加1的timer。
為了更好的演示,我們不修改CartItem
的程式碼。相反的我們要提供一些元件,這些元件會封裝CartItem
並且給CartItem
High-Order Comoentn
。
上面的介紹可能還是有些模糊,不要緊隨著本文步步深入一切都會變得清晰。
我們假設這個Hight-Order Component叫做IntervalEnhance
,存放在一個叫做intervalEnhance.jsx的檔案中。那麼我們的CartItem
應該怎麼改呢?
import React from 'react';
// 1
import {IntervalEnhance} from './IntervalEnhance';
class CartItem extends React.Component {
//...略...
}
//2
export default IntervalEnhance(CartItem);
解釋:
1. 引入高階元件IntervalEnhance
。
2. export高階元件包裝增強後的CartItem
。
下滿就看看告誡元件是怎麼定義的:
//@flow
import React from 'react';
//1
export var IntervalEnhance = ComposeComponent => class extends ComposeComponent {
// 2
static displayName = 'ComponentEnhancedWithIntervalHOC' ;
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}
// 3
componentDidMount() {
this.interval = setInterval(this.tick.bind(this), 1000);
}
// 3
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
this.setState({
seconds: this.state.seconds + 1000
});
}
render() {
return (
// 4
<ComposeComponent {...this.props} {...this.state} />
);
}
}
解釋:
1. ComposeComponent => class extends React.Comonent
這句。還記得箭頭函式嗎?沒錯,這就是一個箭頭函式。這個函式接受一個元件為輸入引數,返回一個類。ComposedComponent
就是輸入引數,也就是需要包裝增強的元件。export var IntervalEnhance
就是把前面定義的函式命名為IntervalEnhance
export出去給其他的模組使用。
2. displayName設定為ComponentEnhancedWithIntervalHOC
是為了在DevTools中方便除錯。在DevTools裡這個元件就會被叫做ComponentEnhancedWithIntervalHOC
。
3. 元件生命週期不同階段的回撥。是React元件的內建方法。
4. 最有意思的就是這裡了。這樣的寫法會把當前高階元件的全部props和state都發送給CartItem
,這樣CartItem
就可以取到this.state.seconds
屬性的值了。
最後我們就需要修改CartItem
元件的內部了。這樣才能輸出this.state.seconds
的值。
import React from 'react';
import {IntervalEnhance} from './IntervalEnhance';
class CartItem extends React.Component {
render() {
return (
<article className="row large-4">
<p className="large-12 column" >
<strong>Time elapsed for interval: </strong>
{this.props.seconds} ms
</p>
</article>
);
}
}
注意:全部都完成都不需要修改CartItem
元件本身(除了render
方法)!這就是為什麼High-Order Component為什麼這裡厲害的原因所在。
使用ES7裝飾器
使用ES7的裝飾器(decorator)程式碼會更加簡潔。
首先,安裝babel-plugin-transform-decorators-legacy
:
npm install --save-dev babel-plugin-transform-decorators-legacy
之後,配置.babelrc檔案:
{
"presets": ["es2015", "react", "stage-0"],
"plugins": [
["transform-decorators-legacy"]
]
}
然後:
import React from 'react';
import {IntervalEnhance} from './intervalEnhance';
@IntervalEnhance
class CartItem extends React.Component {
// ...略...
}
總結
Hight-Order Component(高階元件)非常好用,也可以非常有效的解決問題。當前,使用高階元件非常多的用來代替舊的mixin。
有一個典型的例子就是Relay。Relay也是facebook釋出的一個完全基於React的framework。你的每一個元件都可以包裹在Relay容器中,自動的存取依賴的資料。