React入門與進(jìn)階(首篇)

歡迎訪問我的博客

早期,我們開發(fā)web應(yīng)用,只能是通過請(qǐng)求服務(wù)器,服務(wù)端響應(yīng)請(qǐng)求,返回一個(gè)頁面,,每次瀏覽器都得對(duì)頁面加載,渲染,非常影響用戶體驗(yàn);直到出現(xiàn)了ajax,人們感覺web開發(fā)的春天終于來了,ajax使得我們可以在不刷新整個(gè)頁面的情況下,更新頁面局部,開發(fā)者開始使用各種類庫(kù)在瀏覽器端渲染應(yīng)用,但是隨著應(yīng)用越來越大,這種方式也越來越難整合。

React的設(shè)計(jì)思路是將請(qǐng)求發(fā)生時(shí)渲染整個(gè)頁面這種工作流放到客戶端中。

React初識(shí)

狀態(tài)

首先,我們需要了解一下狀態(tài)與狀態(tài)機(jī)的概念:

  • 狀態(tài)

狀態(tài)就是一種事物在之前一段時(shí)間經(jīng)過人為或自主發(fā)展后的表現(xiàn)結(jié)果。在一個(gè)web應(yīng)用中,狀態(tài)是指經(jīng)過用戶操作,交互后應(yīng)用的表現(xiàn)結(jié)果。

  • 狀態(tài)機(jī)

對(duì)于一組狀態(tài),隨著時(shí)間變化,根據(jù)不同的輸入,各狀態(tài)不斷進(jìn)行轉(zhuǎn)換,狀態(tài)機(jī)即負(fù)責(zé)管理不同狀態(tài)間的轉(zhuǎn)換。

React特性

在以前,每次交互后,應(yīng)用狀態(tài)變化,我們需要重新渲染整個(gè)頁面,這是很慢的;盡管后來有了ajax,我們得以使用ajax異步請(qǐng)求數(shù)據(jù),然后使用JavaScript查詢獲取DOM,使用新數(shù)據(jù)更新DOM,比原來體驗(yàn)好了許多,但這也必然引起瀏覽器對(duì)頁面的重繪或重排,也有性能局限,我們的程序員又踏上了更高的追求。

React主要只負(fù)責(zé)兩件事,都只和View視圖相關(guān):

1. 更新DOM
1. 響應(yīng)事件
  • 更新DOM

React使用了虛擬DOM(Virtual DOM)構(gòu)造一個(gè)強(qiáng)悍的渲染系統(tǒng):通過內(nèi)部渲染函數(shù)計(jì)算出盡量少的DOM更新,觸發(fā)最少的重繪改變應(yīng)用的狀態(tài),為用戶提供更友好的體驗(yàn)。

渲染函數(shù),可以讀取特定時(shí)間或操作下應(yīng)用頁面的狀態(tài),并將其轉(zhuǎn)換為頁面上的虛擬表現(xiàn)(這些虛擬表現(xiàn)由Virtual DOM構(gòu)成),通過比較不同的虛擬表現(xiàn),可以計(jì)算出狀態(tài)改變后最少的DOM變化,提供給React的渲染系統(tǒng)。

  • 響應(yīng)事件

React只使用單個(gè)事件處理器,將所有事件委托給此事件處理器,使得應(yīng)用更高效的處理所有事件。

JSX

除了使用原生JavaScript語法編寫React應(yīng)用,React還提供一種在組件內(nèi)構(gòu)建標(biāo)簽的類XML語法--JSX(JavaScript XML)。


    // 舊版本React原生JavaScript語法
    var title1 = React.DOM.h1({className: 'react'}, 'React');

    // 新版本React原生JavaScript語法
    var title2 = React.createElement('h1', {className: 'react'}, 'React');

    // JSX語法
    var title3 = React.createClass({            
        render: function() {                
            return (
                <div onClick={this.handleClick}>
                    <h1 className="react">
                    React, {this.label_txt}
                    </h1>
                    <div className="component-cont">
                        {this.props.children}
                    </div>
                    <p>{this.dateToString(new Date())}</p>
                </div>
            );
        },
        handleClick: function() {
        }
    });

和原生JavaScript語法不同,如果使用了JSX語法,我們需要將其轉(zhuǎn)換成原生js執(zhí)行:

JSXTransformer.js

React提供JSXTransformer.js轉(zhuǎn)換JSX語法,需要引入JSXTransformer.js并且將script標(biāo)簽type設(shè)置為text/jsx:


    <script type="text/jsx" src=""></script>
    <script type="text/jsx">...</script>

如圖:

JSXTransformer.js

babel

也可以使用babel轉(zhuǎn)換JS語法:引入babel的browser.js,并且將script標(biāo)簽type設(shè)置為text/babel

babel
    
    <script type="text/babel" src=""></script>
    <script type="text/babel">...</script>

注:使用JSX語法后,如果是引入外部js文件的形式,瀏覽器會(huì)請(qǐng)求文件失敗,且這種語法轉(zhuǎn)換較慢,盡量在服務(wù)端預(yù)先轉(zhuǎn)換語法。

React Component

React推薦創(chuàng)建組件處理特定需求,在應(yīng)用中組合使用組件,實(shí)現(xiàn)特定功能。

單向數(shù)據(jù)流

React組件是一個(gè)狀態(tài)機(jī),每個(gè)組件內(nèi)部都有自己的狀態(tài)(state),其狀態(tài)只在內(nèi)部作用域下操作修改。多個(gè)組件之間可以是復(fù)合的關(guān)系,即從屬組件關(guān)系,React組件提供設(shè)置組件屬性(props),屬性可以從主組件獲取傳遞到各屬組件。

主組件與屬組件通信,最簡(jiǎn)單的方式是通過props,主組件通過props傳遞回調(diào)函數(shù)給屬組件,在回調(diào)函數(shù)里可以更新state,觸發(fā)組件重繪;在屬組件中調(diào)用回調(diào)函數(shù),也可以傳入數(shù)據(jù)參數(shù)。

props

props即屬性,我們可以給React組件設(shè)置屬性,屬性值可以是任意JavaScript數(shù)據(jù)類型,且在組件內(nèi)應(yīng)該是只讀的。

  • this.props

我們可以通過this.props訪問到所有組件屬性,但是該屬性值是只讀的。

  • 掛載組件屬性

可以在掛載組件時(shí)傳入組件props,指定其屬性值:


    var HelloReact = React.createClass({
        render: function() {
            return (
                <h1>{this.props.greetWord}</h1>
            );
        }   
    });
    
    var greet = "Hello, React";
    React.render(
        <HelloReact greetWord={greet} />,
        document.querySelector('body')
      );
  • getDefaultProps

在創(chuàng)建組件時(shí),可以定義getDefaultProps方法為組件設(shè)置默認(rèn)屬性值,該方法在調(diào)用創(chuàng)建組件類方法時(shí)即被調(diào)用:


    var HelloReact = React.createClass({
        getDefaultProps: function() {
            return {
                name: 'coding'
            };
        }
        // ...
    });
  • setProps

我們也可以使用setProps()方法設(shè)置組件屬性,但是只能在組建外或者子組件中調(diào)用該方法:


    var HelloReact = React.createClass({
        render: function() {
            return (
                <h1>{this.props.greetWord}</h1>
            );
        }
    });

    var helloReact = React.render(
        <HelloReact greetWord={greet} />,
        document.querySelector('body')
      );
    helloReact.setProps({greetWord: 'Hello, world!'});
  • PropTypes

React提供了一種驗(yàn)證props的方式:定義一個(gè)propTypes對(duì)象,指定組件屬性應(yīng)該滿足的數(shù)據(jù)類型,若不滿足則會(huì)輸出一條console.warn語句:

    
    var HelloReact = React.createClass({
        propTypes: {
            greetWord: React.PropTypes.func
        },
        render: function() {
            return (
                <h1>{this.props.greetWord}</h1>
            );
        }
    });

    var helloReact = React.render(
        <HelloReact greetWord={greet} />,
        document.querySelector('body')
    );

state

我們說每一個(gè)組件都是一個(gè)狀態(tài)機(jī),管理著各自的狀態(tài),就是所謂的state,state只存在于組件的內(nèi)部。

  • this.state

可以通過this.state訪問組件狀態(tài)值。

  • getInitialState

React組件state默認(rèn)是null,在定義組件類時(shí)我們可以定義getInitialState方法指定組件初始state值。


    var HelloReact = React.createClass({
        getInitialState: function() {
            return {
                isShowContent: false
            };
        },
        render: function() {
            if (this.state.isShowContent) {
                return (
                    <div>state modified</div>
                );
                    }
            return (
                <h1>{this.props.greetWord}</h1>
            );
        }
    });

    var helloReact = React.render(
        <HelloReact greetWord={greet} />,
        document.querySelector('body')
    );
  • setState

在組件渲染到頁面后,我們可以通過setState方法修改組件狀態(tài)值,state變化后會(huì)自動(dòng)調(diào)用render方法,重新渲染DOM。


    var HelloReact = React.createClass({
        getInitialState: function() {
            return {
                isShowContent: false
            };
        },
        render: function() {
            if (this.state.isShowContent) {
                return (
                    <div>state modified</div>
                );
                    }
            return (
                <h1 onClick={this.handleClick}>{this.props.greetWord}</h1>
            );
        },
        handleClick: function() {
            this.setState({
                isShowContent: !this.state.isShowContent
            });
        }
    });

    var helloReact = React.render(
        <HelloReact greetWord={greet} />,
        document.querySelector('body')
    );
  • replaceState

更新組件狀態(tài)有兩種方法:setState和replaceState,和前者在原有state對(duì)象上拓展不同,replaceState是使用傳入的參數(shù)直接替換原有的state。

永遠(yuǎn)不要通過setState和replaceState方法以外的方式更新state,如:this.state.isShowContent = true;,這樣更新state,React無法監(jiān)控,組件無法重新渲染。

props & state

state只存在與組件內(nèi)部,它應(yīng)該只是對(duì)應(yīng)組件視圖的某一種狀態(tài),是一種簡(jiǎn)單的值,任何不必要的或通過計(jì)算得出的值都不應(yīng)該在這里出現(xiàn)。

如果需要在組件樹中傳遞或給特定組件傳入數(shù)據(jù),可以通過props給上層組件設(shè)置屬性值,可以是任意類型的數(shù)據(jù);一旦屬性傳入組件,其應(yīng)該是只讀的。

組件的生命周期

每個(gè)組件擁有其生命周期:從實(shí)例化,到生存期,到被銷毀。

實(shí)例化

當(dāng)一個(gè)組件在首次實(shí)例化時(shí),調(diào)用的生命周期方法依次為:

1. getDefaultProps
2. getInitialState
3. componentWillMount
4. render
5. componentDidMount

在組件的后續(xù)應(yīng)用,則會(huì)依次調(diào)用如下方法:

1. getInitialState
2. componentWillMount
3. render
4. componentDidMount
  • getDefaultProps

該方法返回一個(gè)對(duì)象設(shè)置實(shí)例的默認(rèn)props值,在調(diào)用定義組件類方法時(shí)調(diào)用且只調(diào)用一次。

  • getInitialState

此方法可以初始化每個(gè)實(shí)例的state,每次實(shí)例化都只會(huì)調(diào)用一次。

  • componentWillMount

該方法在組件完成首次渲染之前調(diào)用,此時(shí)可以修改組件state。

  • render

此方法創(chuàng)建虛擬DOM,返回一個(gè)虛擬表現(xiàn);此方法是定義組件類是必需定義地方法。

  • componentDidMount

此方法在render方法成功返回值,且真實(shí)DOM在頁面渲染完成之后,調(diào)用,經(jīng)常通過this.getDOMNode()方法獲取真實(shí)DOM節(jié)點(diǎn)。

生存期

組件渲染好,在頁面中生成DOM并且可以與用戶交互,即是組件的生存期。

在生存期,隨著用戶的交互,可能觸發(fā)的生存期方法有:

1. componentWillReceiveProps
2. shouldComponentUpdate
3. componentWillUpdate
4. componentDidUpdate
  • componentWillReceiveProps

React組件的props在其指定或被上級(jí)組件更改時(shí),將觸發(fā)此方法,此方法接收一個(gè)參數(shù):更改后的props,我們可以在此方法內(nèi)根據(jù)props值更改組件內(nèi)部state值。

  • shouldComponentUpdate

在組件首次渲染完后,如果我們改變了組件props或state值,將觸發(fā)此方法,若該組件及其下級(jí)組件都不需要渲染新的props和state,則此方法返回false,不會(huì)調(diào)用render()方法,否則,返回true,調(diào)用render()方法重新渲染組件。我們可以自定義覆蓋該方法,優(yōu)化該組件決定是否重新渲染組件的規(guī)則,獲得更適合需求的用戶體驗(yàn)。

  • componentWillUpdate

組件接收新的props或state后,render()方法觸發(fā)前將調(diào)用此方法。

注:不要在此方法內(nèi)更新state.

  • componentDidUpdate

組件接收新的props或state后,render()方法觸發(fā),組件渲染好后將調(diào)用此方法。

銷毀

在使用完React組件后,我們需要將其從頁面文檔移除銷毀。

  • componentWillUnmount

當(dāng)一個(gè)組件被移除時(shí),將觸發(fā)componentWillUnmount()方法,我們可以在此方法內(nèi)清理之前的一些引用或事件監(jiān)聽程序。

事件處理

前文提到,React主要關(guān)注兩件事:更新DOM,響應(yīng)事件。關(guān)于更新DOM,前文已經(jīng)闡述,接下來要學(xué)習(xí)React的單一事件處理器。

組件相當(dāng)于一個(gè)狀態(tài)機(jī),其提供給用戶一個(gè)視圖(view),組件內(nèi)部狀態(tài)(state)對(duì)應(yīng)特定的視圖表現(xiàn),用戶與視圖交互時(shí),我們通過在組件上綁定事件處理器監(jiān)聽用戶輸入,事件觸發(fā)時(shí),在事件處理器中更新組件狀態(tài)(state),React根據(jù)state值的變化決定是否更新(重繪或重新渲染)組件,組件在render方法內(nèi)渲染新的state數(shù)據(jù),更新視圖表現(xiàn)。

綁定事件處理器

React綁定事件處理器寫法類似HTML內(nèi)聯(lián)事件寫法,但其本質(zhì)是通過事件代理實(shí)現(xiàn)的:


    render: function() {
            if (this.state.isShowContent) {
                return (
                    <div>state modified</div>
                );
                    }
            return (
                <h1 onClick={this.handleClick}>{this.props.greetWord}</h1>
            );
        }

React支持的事件類型可以參考:http://facebook.github.io/react/docs/events.html

觸摸事件

若需要在React中使用觸摸事件,則需要手動(dòng)調(diào)用開啟:React.initializeTouchEvents(true);

事件與狀態(tài)

只有組件的props或state變化才會(huì)觸發(fā)組件重繪和渲染,如果組件需要隨用戶交互輸入改變視圖表現(xiàn),則需要在事件處理程序里更新組件state。


    var HelloReact = React.createClass({
        getInitialState: function() {
            return {
                isShowContent: false
            };
        },
        render: function() {
            if (this.state.isShowContent) {
                return (
                    <div>state modified</div>
                );
                    }
            return (
                <h1 onClick={this.handleClick}>{this.props.greetWord}</h1>
            );
        },
        handleClick: function(event) {
            this.setState({
                isShowContent: !this.state.isShowContent
            });
        }
    });

    React.render(
            React.createElement(title3, null, 'this is my react practice.'),
            document.querySelector('.main')
    );

線上地址:點(diǎn)此查看效果

事件對(duì)象

和原生DOM事件一樣,React事件處理器函數(shù)會(huì)傳入一個(gè)事件對(duì)象。React并不是直接把原生DOM的事件對(duì)象傳給事件處理器函數(shù),而是封裝在SyntheticEvent對(duì)象中,但其使用和原始事件對(duì)象保持一致,并且可以通過其nativeEvent屬性獲取原生事件對(duì)象:


    handleClick: function(event) {
        console.log(event);
        console.log(event.nativeEvent);
        this.setState({
            isShowContent: !this.state.isShowContent
        });
    }

輸出如下:

React事件對(duì)象與原生事件對(duì)象

線上地址,可以打開控制臺(tái)查看打印消息。:點(diǎn)此查看效果

對(duì)于有一定基礎(chǔ)的前端同學(xué),經(jīng)過本篇學(xué)習(xí),應(yīng)該可以使用React編寫一個(gè)基本的程序了,接下來將深入學(xué)習(xí)React組件復(fù)合,通信。

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

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

  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個(gè)人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,942評(píng)論 1 18
  • 本筆記基于React官方文檔,當(dāng)前React版本號(hào)為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,930評(píng)論 14 128
  • 我們?cè)谝巴獾纳掷锒冗^了一夜,覺得還不錯(cuò)。第二天早上我和同伴早早的起來了,興奮的期待著這一天會(huì)怎樣發(fā)展。 有幾個(gè)同...
    紫幽水仙f1d9閱讀 288評(píng)論 0 0
  • 在農(nóng)村,像我們孩子這么大的小朋友早就會(huì)騎自行車了,可是我們孩子,因?yàn)槟懽有?,因?yàn)槲覀兪冀K沒有教他學(xué)騎車,所以他就一...
    西瓜甜甜啦閱讀 677評(píng)論 29 30
  • 看著一道色彩妖艷的美食,聞著一股讓人神魂顛倒的香氣,你還能保持一顆平靜的心嗎?作為一個(gè)純粹的美食愛好者,每天烹制各...
    詩(shī)樺閱讀 4,167評(píng)論 38 106

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