01.構(gòu)建第一個React應(yīng)用(一)

第一個基于React應(yīng)用為一個投票的app,效果圖如下顯示:

voting-app.jpeg

點擊藍色的小三角對應(yīng)的票數(shù)會增加。
github源碼地址

使用create-react-app來構(gòu)建React應(yīng)用。具體的使用方法參考React官方教程create-react-app使用。安裝好create-react-app以后來構(gòu)建我們的第一個簡單的項目。
構(gòu)建方法如下:

create-react-app voting-app 
cd voting-app
yarn start

當(dāng)網(wǎng)頁如下顯示以后表明應(yīng)用啟動成功:


first-react-app.jpeg

項目結(jié)構(gòu)如下:


project-structure.jpeg

public/index.html更改一下index.html的結(jié)構(gòu)

    <div class="main ui text container">
      <h1 class="ui dividing centered header">Popular Products</h1>
      <div id="root"></div>
    </div>

這里的<div id="root"></div>是React應(yīng)用的掛載點,后面會具體提到。樣式使用了semantic ui,在該文件中引入對應(yīng)的樣式文件即可。


什么是組件?
構(gòu)建一個React的核心就是組件。一個獨立的React組件可以被認(rèn)為是一個app中的UI組件。我們可以將voting-app劃分成兩個主要的組件:

組件劃分.jpeg

從圖中我們可以看出有一個父組件包含了許多子組件,并且分別稱他們?yōu)?code>ProductList和Product

  • ProductList:包含許多product組件
  • Product:顯示信息

每個組件可以包含標(biāo)簽,視圖邏輯,組件樣式,交互事件等。也就是說,一個組件中可以包含HTML結(jié)構(gòu),CSS樣式,JavaScript事件。這使得React組件有很好的復(fù)用性。(這和傳統(tǒng)的HTML,CSS,JavaScript分離的觀念不同)。
此外,React對于組件的數(shù)據(jù)流和交互性是嚴(yán)格限制的。在React中,當(dāng)一個組件的輸入發(fā)生了變化,那么組件也會重新渲染,所以這使得數(shù)據(jù)和UI的一致性得到了保障:只要給定的數(shù)據(jù)輸入不發(fā)生變化,那么其輸出(組件在頁面上的顯示)則始終保持一致。
根據(jù)上面的project-structure圖來建立兩個組件(都是js文件)。

ProductList.js

import React, { Component } from 'react'
class ProductList extends Component {
  render () {
    return (
      <div className="ui unstackable items">
      </div>
    )
  }
}

export default ProductList

React組件是一個繼承與React.ComponentES6 class。ProductList類中有一個方法名為render(),這個方法是一個組件中必須存在的一個方法,其返回值會決定將什么渲染到頁面上。
(關(guān)于ES6類的用法可以參考阮一峰老師的ES6入門。class基本語法,class的繼承)

如果你熟悉JavaScript,你會對render返回的值感到奇怪:

 return (
      <div className="ui unstackable items">
        some text
      </div>
)

這個返回值看起來并不像傳統(tǒng)的JavaScript,而看上去更像HTML。其實這是一種稱之為JSX(JavaScript eXtension syntax)的語法。這是由Facebook對JavaScript的一種語法拓展。使用JSX可以讓我們寫出HTML-like的語法來渲染頁面。其實JSX的本質(zhì)就是JavaScript對象,可以使用編譯器(如babel)將JSX翻譯成JavaScript對象。
JSX:

<div className="ui item">
  some text
</div>

則會翻譯成:

React.createElement(
  'div', 
  {className: "ui item"},
  'some text'
)

總結(jié)一下JSX:
React組件最終都會被渲染成HTML顯示在頁面上。而render()方法則是描述view應(yīng)該如何被HTML表示。React使用一種偽DOM(fake DOM)來構(gòu)建app,這個偽DOM稱之為虛擬DOM(virtual DOM),之后會具體闡述什么是虛擬DOM(很重要的一個概念)。所以,React可以讓我們以JavaScript的方式來描述組件的HTML。


如何將組件顯示到頁面上?
index.js中:

import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';

import ProductList from './components/ProductList'

ReactDOM.render(<ProductList />, document.getElementById('root'));
registerServiceWorker();

其他的先不管,具體來看看ReactDOM.render()方法。
ReactDOM來自于react-dom庫,該方法接受兩個參數(shù),第一個參數(shù)是我們想要渲染什么(what),第二個參數(shù)是渲染到哪里(where):
ReactDOM.render(what, where)
這里,what就是我們剛剛創(chuàng)建的組件ProductList,它由import ProductList from './components/ProductList'導(dǎo)入。而where則是在index.html中的`<div id="root"></div>"中。相當(dāng)于將React的組件渲染到這個節(jié)點下。
注意:自定義組件的首字母必須大寫,否則React會將其看作HTML標(biāo)簽來渲染,從而導(dǎo)致錯誤。
保存以后可以看看頁面上的顯示效果(每次保存文件后,瀏覽器會自動刷新)。


創(chuàng)建Product
現(xiàn)在讓我們來創(chuàng)建子組件Product。同樣的,我們使用ES6的class來創(chuàng)建該組件:

import React, { Component } from 'react'

class Product extends Component {
  render () {
    return (
      <div className="item">
        {/* todo... 這是React中的注釋方法 */}
      </div>
    )
  }
}

export default Product

組件可以以組合的方式來構(gòu)建,所以在父組件中可以嵌套子組件,由之前的組件劃分我們可以將Product組件放入ProductList組件中:

import React, { Component } from 'react'
import Product from './Product'
class ProductList extends Component {
  render () {
    return (
      <div className="ui unstackable items">
        <Product/>
      </div>
    )
  }
}

export default ProductList

數(shù)據(jù)驅(qū)動的Product組件
創(chuàng)建一個products.json文件,里面的具體內(nèi)容可以參考代碼。

使用props
我們將修改Product組件,這樣就可以不使用靜態(tài)的,硬編碼的數(shù)據(jù)了。我們想要從父組件ProductList中將數(shù)據(jù)傳遞到子組件Product中。數(shù)據(jù)的流向如下:

data-flow.jpeg

數(shù)據(jù)是以props的方式從父組件傳遞到子組件。

現(xiàn)在讓我們修改ProductList,使用props來向Product傳遞數(shù)據(jù),然后渲染:
ProductList.js

import products from '../products.json'
class ProductList extends Component {
  render () {
    const product = products[0]
    const productComponents =  (
          <Product
            id={product.id}
            title={product.title}
            description={product.description}
            url={product.url}
            votes={product.votes}
            submitterAvatarUrl={product.submitterAvatarUrl}
            productImageUrl={product.productImageUrl}/>
        )
    })
    return (
      <div className="ui unstackable items">
        {productComponents}
      </div>
    )
  }
}

這里,變量product是用于藐視第一個products的JavaScript對象。我們以一種類似于HTML中的屬性的屬性方式在組件上寫屬性,而這個[propName]=[propValue]的語法方式就是props的用法。這樣子組件就可以通過一種方式來獲取這些“屬性”和“屬性值”。
當(dāng)然,這里還有兩個有趣的地方。第一個是在每個屬性值外包括的花括號{}
id={product.id}
在JSX中,花括號是一種定界符,用來告訴JSX花括號中的內(nèi)容是JavaScript表達式
另一個定界符是使用引號""來引用字符串,就像這樣:id="1"。所以,id={1}這里的id的內(nèi)容是數(shù)字1,而id="1"的id內(nèi)容是字符串1。

現(xiàn)在ProductList已經(jīng)通過props的方式將數(shù)據(jù)傳遞給了Product,那么在Product中如果得到這些數(shù)據(jù)呢?現(xiàn)在讓我們修改Product以獲取這些數(shù)據(jù)。

render () {
    return (
      <div className="item">
        <div className="image">
          <img src={this.props.productImageUrl} alt=""/>
        </div>
        <div className="middle aligned content">
          <div className="header">
            <a onClick={this.handleUpVote}>
              <i className="large caret up icon"></i>
            </a>
            {this.props.votes}
          </div>
          <div className="description">
            <a href={this.props.url}>{this.props.title}</a>
            <p>{this.props.description}</p>
          </div>
          <div className="extra">
            <span>Submitted by: </span>
            <img src={this.props.submitterAvatarUrl} className="ui avatar image" alt=""/>
          </div>
        </div>
      </div>
    )
  }

可以看出,這里是用this.props.xxx的方式來獲取props的值。
在HTML元素中使用props的方式可以讓我們創(chuàng)建動態(tài),數(shù)據(jù)驅(qū)動的React組件。

保存文件以后,可以看到瀏覽器已經(jīng)渲染出一個列表了。


渲染多個products
為了渲染多個products,我們需要讓ProductList產(chǎn)生一個Product組件數(shù)組,每個Product組件用于渲染特定的數(shù)據(jù)。我們可以使用JavaScript中的map()方法來產(chǎn)生一組特定的Product組件數(shù)組。map的解釋
ProductList.js:

render () {
    const productComponents = products.map(product => {
      return (
          <Product
            key={`product-${product.id}`}
            id={product.id}
            title={product.title}
            description={product.description}
            url={product.url}
            votes={product.votes}
            submitterAvatarUrl={product.submitterAvatarUrl}
            productImageUrl={product.productImageUrl}
            onVote={this.handleProductUpVote}/>
        )
    })
    return (
      <div className="ui unstackable items">
        {productComponents}
      </div>
    )

這里新添加的key屬性很重要,必須添加,以后會詳細解釋為什么
保存文件,瀏覽器上就能顯示一個Product列表了。

現(xiàn)在再修改一下,讓頁面以票數(shù)從小到大來顯示。其實很簡單,只要將products數(shù)據(jù)做一個排序就可以了,可以使用sort()方法。sort的解釋
ProductList.js:

render () {
    const sortedProducts = this.state.products.sort((a, b) => a.votes - b.votes)
    const productComponents = sortedProducts.map(product => {
      return (
          <Product
            key={`product-${product.id}`}
            id={product.id}
            title={product.title}
            description={product.description}
            url={product.url}
            votes={product.votes}
            submitterAvatarUrl={product.submitterAvatarUrl}
            productImageUrl={product.productImageUrl}
            onVote={this.handleProductUpVote}/>
        )
    })
    return (
      <div className="ui unstackable items">
        {productComponents}
      </div>
    )

此時,瀏覽器的頁面渲染效果如下:


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

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

  • 本筆記基于React官方文檔,當(dāng)前React版本號為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,931評論 14 128
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,944評論 1 18
  • 深入JSX date:20170412筆記原文其實JSX是React.createElement(componen...
    gaoer1938閱讀 8,182評論 2 35
  • GUIDS 第一章 為什么使用React? React 一個提供了用戶接口的JavaScript庫。 誕生于Fac...
    jplyue閱讀 3,704評論 1 11
  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時,對React的特性、重點和注意事項的提取、精練和總結(jié),可以做為React特性...
    科研者閱讀 8,408評論 2 21

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