1. 程式人生 > >React與ES6(四)ES6如何處理React mixins

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容器中,自動的存取依賴的資料。