React與ES6系列:
- React與ES6(一)開篇介紹
- React和ES6(二)ES6的類和ES7的property initializer
- React與ES6(三)ES6類和方法綁定
- 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);
解釋:
- 引入高階組件
IntervalEnhance
。 - 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} />
);
}
}
解釋:
ComposeComponent => class extends React.Comonent
這句。還記得箭頭函數嗎?沒錯,這就是一個箭頭函數。這個函數接受一個組件為輸入參數,返回一個類。ComposedComponent
就是輸入參數,也就是需要包裝增強的組件。export var IntervalEnhance
就是把前面定義的函數命名為IntervalEnhance
export出去給其他的模塊使用。- displayName設定為
ComponentEnhancedWithIntervalHOC
是為了在DevTools中方便調試。在DevTools里這個組件就會被叫做ComponentEnhancedWithIntervalHOC
。 - 組件生命周期不同階段的回調。是React組件的內置方法。
- 最有意思的就是這里了。這樣的寫法會把當前高階組件的全部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容器中,自動的存取依賴的數據。