React和ES6(二)ES6的類和ES7的property initializer

React與ES6系列:

  1. React與ES6(一)開篇介紹
  2. React和ES6(二)ES6的類和ES7的property initializer
  3. React與ES6(三)ES6類和方法綁定
  4. React與ES6(四)ES6如何處理React mixins

前一篇的內(nèi)容太簡單了,會不會很失望。這次就來一個(gè)接近實(shí)際應(yīng)用的例子,對應(yīng)的React的組件也會更加復(fù)雜。這次開發(fā)一個(gè)購物車的頁面。在這個(gè)頁面中你會看到某個(gè)產(chǎn)品的信息,比如:圖片、名稱和價(jià)格。另外,一個(gè)用戶可以增加和減少該商品的數(shù)量。

創(chuàng)建cart_item.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>React and ES6 Part 2</title>
    <link rel="stylesheet" >
</head>
<body>
<div id="root"></div>
<script src="public/cart.bundle.js" type="text/javascript"></script>
</body>
</html>

我們使用了一個(gè)CDN來引用樣式。添加個(gè)樣式美化一下這個(gè)小應(yīng)用的內(nèi)容。dev.root會用來展示React組件生成的內(nèi)容。

CartItem組件

現(xiàn)在開發(fā)Cart組件。創(chuàng)建文件cart.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import CartItem from './cartItem';

const order = {
    title: 'Fresh fruits package',
    image: 'http://images.all-free-download.com/images/graphiclarge/citrus_fruit_184416.jpg',
    initialQty: 3,
    price: 8
};

ReactDOM.render(
    <CartItem title={order.title}
              image={order.image}
              initialQty={order.initialQty}
              price={order.price} />,
    document.getElementById('root')
);

cart.jsx作為購物車功能的總?cè)萜?。這里引入了reactreact-dom。之后引入了CartItem組件,這個(gè)組件會在稍后給出定義。最后,在ReactDom.render方法中把CartItem組件展示在class等于root的HTML元素中。

CartItem組件中的title、image、initialQty和price都是props的值。這些值會在后面CartItem組件的定義中用到。props是組件給子組件傳遞數(shù)據(jù)的一種方式。

CartItem組件初步定義

現(xiàn)在應(yīng)該給出CartItem的定義了。否則整個(gè)web app都無法正常運(yùn)行。CartItem組件可以展示數(shù)據(jù),也可以相應(yīng)用戶的增加、減少操作。

import React from 'react';

export default class CartItem extends React.Component {
    // 1
    constructor(props) {
        super(props);
        this.state = {
            qty: props.initialQty,
            total: 0
        };
    }
    // 2
    componentWillMount() {
        this.recalculateTotal();
    }
    // 3
    increaseQty() {
        this.setState({qty: this.state.qty + 1}, this.recalculateTotal);
    }
    // 3
    decreaseQty() {
        let newQty = this.state.qty > 0 ? this.state.qty - 1 : 0;
        this.setState({qty: newQty}, this.recalculateTotal);
    }
    // 3
    recalculateTotal() {
        this.setState({total: this.state.qty * this.props.price});
    }

    render() {
        return (
            // ...略...  
        );
    }
}

下面解釋一下:

  1. constructor是ES6中類的構(gòu)造函數(shù)。整個(gè)構(gòu)造函數(shù)需要一個(gè)參數(shù)props,其全部的值都在上文的代碼中給出:title、image等。需要注意的是在構(gòu)造函數(shù)中第一個(gè)調(diào)用的是super(props)。this.state = ...一句中,使用props初始化了整個(gè)組件的state初值。
  2. ·componentWillMount()方法是組件的生命周期方法之一。在組件即將在HTML頁面中繪制的時(shí)候調(diào)用。在componentWillMount()中使用方法recalculateTotal()`計(jì)算了商品的總價(jià)。
  3. 這些是增加、減少商品數(shù)量的方法。這些方法在用戶點(diǎn)擊了增加、減少按鈕之后被調(diào)用。在這些方法中,更新了state中物品數(shù)量的值,并在setState方法的回調(diào)中使用了recalculateTotal()方法。

CartItem的render方法

上一節(jié)沒有給出render方法的具體實(shí)現(xiàn),這里給出:

import React from 'react';

export default class CartItem extends React.Component {
    // ...略...

    render() {
        return (
            <article className="row large-4">
                <figure className="text-center">
                    <p>
                        <img src={this.props.image} />
                    </p>
                    <figcaption>
                        <h2>{this.props.title}</h2>
                    </figcaption>
                </figure>

                <p className="large-4 column"><strong>Quantity: {this.state.qty}</strong></p>

                <p className="large-4 column">
                    <button onClick={this.increaseQty.bind(this)} className="button success">+</button>
                    <button onClick={this.decreaseQty.bind(this)} className="button alert">-</button>
                </p>

                <p className="large-4 column"><strong>Price per item:</strong> ${this.props.price}</p>

                <h3 className="large-12 column text-center">
                    Total: ${this.state.total}
                </h3>

            </article>
        );

    }
}

render()方法中,我們使用了JSX語法添加了各種“HTML”節(jié)點(diǎn)。這些節(jié)點(diǎn)和HTML標(biāo)簽很像,但是并不是HTML元素。

不用擔(dān)心this.decreaseQty.bind(this)之類的用法。這些會在下一篇里詳細(xì)解釋。

React在ES6中的Default Props和Props類型

假設(shè)我們現(xiàn)在需要給CartItem添加一些默認(rèn)的props,并可以自動檢查props的類型。

幸好這些在React里都有內(nèi)置支持。所以,相關(guān)代碼非常少。

CartItem類定義的下面直接添加下面的代碼:

CartItem.propTypes = {
    title: React.PropTypes.string.isRequired,
    price: React.PropTypes.number.isRequired,
    initialQty: React.PropTypes.number
};

CartItem.defaultProps = {
    title: "Indefined Product",
    price: 100,
    initialQty: 0
};```
這時(shí)候如果你在*cart.jsx*文件中給`CartItem`的title值為數(shù)值的話,你就會在瀏覽器中看到警告。

##在項(xiàng)目中使用ES7
你可能要問了ES6還沒整明白的就開始用上ES7了?我要說的是我們往前看,使用一些已經(jīng)在靜態(tài)語言里有的特性并不會造成太大的問題。最關(guān)鍵的問題是`Babel`已經(jīng)支持了。

首先安裝必要的`Babel`模塊:`npm install --save-dev babel-preset-stage-0`。

然后在*.babelrc*文件中添加這個(gè)preset的配置:
```js
{
    "presets": ["es2015", "react", "stage-0"]
}

ES7屬性初始化器和React組件的Default Props、Props Types

CartItem類里,添加如下代碼:

export default class CartItem extends React.Component {
    static propTypes = {
        title: React.PropTypes.string.isRequired,
        price: React.PropTypes.number.isRequired,
        initialQty: React.PropTypes.number
    };
    static defaultProps = {
        title: 'Undefined Product',
        price: 100,
        initialQty: 0
    };

    constructor(props) {
        super(props);
        this.state = {
            qty: props.initialQty,
            total: 0
        };
    }

// ...略...

這樣的定義和前面一節(jié)在類定義后面再定義default props和props types是一樣的效果。但是這樣的定義是不是更加的接近靜態(tài)語言類中定義屬性的方式呢?當(dāng)然之前的default props和props types的定義也可以刪去了。

ES7的方式定義React組件的State

最后一步就是把initial state(state初始值)從constructor里拿出來放到property initializer(屬性初始化器)里。代碼如下:

export default class CartItem extends React.Component {
    state = {
        qty: this.props.initialQty,
        total: 0
    };

    constructor(props) {
        super(props);
        // this.state = {
        //     qty: props.initialQty,
        //     total: 0
        // };
    }

    //...略...
}

記得把原來constructor里的state代碼刪了。

總結(jié)

通過這篇你就可以熟悉了如何用ES6寫React的組件,也熟悉了如何使用ES7的property initializer。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容