初識React,Virutal DOM, State以及生命周期

来源:http://www.cnblogs.com/darrenji/archive/2016/05/17/5502989.html
-Advertisement-
Play Games

這是React分類下的第一篇文章,是在瞭解了一些基本面後,看 "Tyler" 文章,邊看邊理解邊寫的。 React可以看做是MVC中的V,關註的是視圖層。React的組件就像Angular的Directive,包括了HTML,CSS,JS以及相關數據等。React的組件被定義在了以"JSX"為尾碼的 ...


這是React分類下的第一篇文章,是在瞭解了一些基本面後,看Tyler文章,邊看邊理解邊寫的。


React可以看做是MVC中的V,關註的是視圖層。React的組件就像Angular的Directive,包括了HTML,CSS,JS以及相關數據等。React的組件被定義在了以"JSX"為尾碼的文件中,這些JSX文件會被最終編譯成Javascript文件。



來看一個最基本的寫法:

var HelloWorld = React.createClass({
    render: function(){
        return (
            <div>
                Hello World!
            </div>
        )
    }
});

ReactDOM.render(<HelloWorld />, document.getElementBy('app'));

以上,我們可以瞭解到:

  • 組件創建:React.createClass用來創建組件,接收一個object,render欄位必須有
  • 組件名稱:就像這裡的HelloWorld,通常是大寫
  • 組件渲染:通過ReactDOM.render來渲染組件,該方法接收2個參數,一個參數代表組件,另一個代表渲染的位置
  • 組件的呈現方式:組件是以類似HTML元素的形式呈現的,另外,如果組件中有變數,變數會以類似HTML元素屬性的形式呈現
  • JSX:以上的的<div>Hello World!</div>和通常的HTML代碼不一樣,是放在以jsx為尾碼的文件中的,最終會被轉換成一個Javascript對象,最終React會創建一個"virtual DOM",React會通過React.createElement("div", null, "Hello Wolrd")創建虛擬的DOM。


1、React在"virtual DOM"這部分是如何工作的?


→ 檢查數據發生變化的部分
→ 重新渲染virutal DOM
→ 與上一次的virtual DOM進行比較
→ 在實際DOM上只更新發生變化的部分


2、State


var HelloUser = React.createClass({
    getInitialState: function(){
        return {
            username: 'firstusername'
        }
    },
    render: function(){
        return (
            <div>
                Hello {this.state.username}
            </div>
        )
    }
});
  • 設置組件初始狀態:通過getInitialState方法返回object對象,為state中的欄位賦值
  • 獲取組件狀態:通過this.state.欄位名來獲取欄位狀態
  • 設置組件狀態:setState雖然在上面沒有提及,但這個方法時被用來真正設置組件狀態的。而且這個setState方法是最常用的,當頁面有數據變化,Reacct會觸發setState方法,渲染virtual DOM,與上一次的virtual DOM進行比較,最後更新發生變化的部分。


2.1 通過事件改變狀態


以上,是通過getInitialState方法設置了一個初始狀態,如何通過事件來觸發改變狀態呢?比如有一個<input>,通過它的onChange方法來觸發改變狀態。


var HelloUser = React.creatClass({
    getInitialState: function(){
        return {
            username: 'darren'
        }
    },
    handleChange: function(e){
        this.setState({
            usename: e.target.value
        });
    },
    render: function(){
        return (
            <div>
                Hello {this.state.username}<br/>
                Change Name:<input type="text" value={this.state.username} onChange={this.handleChange}>
            </div>
        )
    }
});
  • input的onChange事件交給了this.handleChange
  • handleChange方法中,通過setState改變變數的狀態,接著,React渲染一個新的virtual DOM, 與上一次的virtual DOM比較差異,最後只更新發生變化的那部分DOM
  • React的onChange方法用來觸發事件


2.2 嵌套組件的狀態傳遞


現在,我們知道瞭如何設置組件的初始狀態,也知道如何如何設置組件的狀態,現在來到另外一個話題:當主鍵有嵌套的時候,如何把父組件的狀態傳遞給子組件呢?


先來看沒有組件嵌套的情況:

var HelloUser = React.createClass({
    render: function(){
        return (
            <div> Hello, {this.props.name}</div>
        )
    }
});

ReactDOM.render(<HelloUser name="darren" />, document.getElementById('app'));
  • 組件在jsx語法中,是以類似頁面元素的形式呈現的,比如這裡的<HelloUser />,組件中的變數,比如這裡的name欄位,在jsx語法中是以屬性名存在的,比如這裡的<HelloUser name="darren">
  • 對ReactDOM來說,它知道<HelloUser name="darren" />就是需要渲染的組件,HelloUser就是組件的名稱,給name賦的值最終賦值給了props屬性


再來看存在組件嵌套的情況下,如何傳遞State。

被嵌套的組件:

var ShowList = React.createClass({
    render: function(){
        var listItems = this.props.names.map(function(friend){
            return <li>{{friend}}</li>;
        });

        return (
            <div>
                <h3>Friends</h3>
                <ul>
                    {listItems}
                </ul>
            </div>
        )
    }
});

以上,ShowList組件的視圖渲染需要外界給names欄位賦上數組。也就是<ShowList names=... />中names屬性需要賦值。從哪裡賦值呢?可以從嵌套組件的state中獲取。


好,那就來到嵌套組件:

var ParentContainer = React.createClass({
    getIntitialState: function(){
        return {
            name: 'darren',
            friends:['a','bob']
        }
    },
    render: function(){
        return (
            <div>
                <h3>Name: {this.state.name}</h3>
                <ShowList names={this.state.friends}>
            </div>
        )
    }
});
  • 我們知道getIntitialState中返回對象的各個欄位是放在了state中的
  • state中的friends是數組,賦值給了ShowList的names屬性
  • 嵌套組件和被嵌套組件之間state的傳遞看上去像一條河流,嵌套組件是河流的上游,被嵌套組件是下游,河水是單向流動的,上游的state向下游流動,傳遞給了下流的被嵌套組件


現在,組件看起來就像C#中對類的封裝。React的組件是否和C#中的類有更多的相似性呢?


假設,在顯示朋友列表的頁面再增加一塊區域,用來添加朋友信息。那,我們有必要為這一塊添加的區域定義一個組件:

var AddFriend = React.createClas({
    getIntialState: function(){
        return {
            newFriend: ''
        }
    },
    updateNewFriend: function(e){//更新就是為state的newFriend欄位賦上當前的值
        this.setState({
            newFriend: e.target.value
        });
    },
    handleAddNew: function(){
        this.props.addNew(this.state.newFriend);
        this.setState({
            newFriend: ''
        });
    },
    render: function(){
        return (
            <div>
                <input type="text" value={this.state.newFriend} onChange={this.updateNewFriend} />
                <button onClick={this.handleAddNew}>Add Friend</button>
            </div>
        )
    }
});
  • input文本框的值取決於state中的newFriend欄位值
  • 為input添加了onChange事件,該事件由updateNewFriend這個代表函數的欄位所定義
  • 在updateNewFriend函數中,把文本框的當前值賦值給state中的newFriend欄位
  • 為button添加了一個onClick事件,該事件由handleAddNew所代表函數的欄位所定義,而在handleAddNew函數內部,props屬性需要由外界來賦值。會類似<AddFriend addNew={...} />這樣的形式呈現


以上的AddFriend組件是也是一個被嵌套組件,它和ShowList組件被一起嵌套在ParentContainer這個組件中。


於是,就來到了ParentContainer這個組件。

var ParentContainer = React.createClass({
    getInitialState: function(){
        return {
            name: 'darren',
            friends: ['a','b']
        }
    },
    addFriend: function(friend){
        this.setState({
            this.setState({
                friends: this.state.friends.concat([friend])
            });
        });
    },
    render: function(){
        return (
            <div>
                <h3>Name: {this.state.name}</h3>
                <AddFriend addNew={this.addFriend} />
                <ShowList names={this.state.friends} />
            </div>
        )
    }
});

被嵌套組件所需要的,都通過嵌套組件的state或函數獲得。


2.3 設置組件的屬性類型


在上面的AddFriend組件中,button是這樣的:<button onClick={this.handleAddNew}>Add Friend</button>,button的點擊事件由handleAddNew函數決定,而handleAddNew函數由this.props.addNew(this.state.newFriend)所決定,addNew函數是props屬性的函數類型欄位,是否可以定義呢?答案是可以。


var AddFriend = React.createClas({
    getIntialState: function(){
        return {
            newFriend: ''
        }
    },
    propTypes: {
        addNew: React.PropTypes.func.isRequired
    },
    updateNewFriend: function(e){//更新就是為state的newFriend欄位賦上當前的值
        this.setState({
            newFriend: e.target.value
        });
    },
    handleAddNew: function(){
        this.props.addNew(this.state.newFriend);
        this.setState({
            newFriend: ''
        });
    },
    render: function(){
        return (
            <div>
                <input type="text" value={this.state.newFriend} onChange={this.updateNewFriend} />
                <button onClick={this.handleAddNew}>Add Friend</button>
            </div>
        )
    }
});


3、組件的生命周期


組件的生命周期又是怎樣的呢?

var FriendsConainer = React.createClass({
    getInitialState: function(){
        alert('getInitialState');
        return {
            name: 'darren'
        }
    },
    componentWillMount: function(){},
    componentDidMount: function(){},
    componentWillReceiveProps: function(nextProps){},
    componentWillUnmount: function(){},
    render: function(){
        return (
            <div>
                Hello, {this.state.name}
            </div>
        )
    }
});
  • componentWillMount:初次渲染之前調用一次
  • componentDidMount:初次渲染之後調用,這時,可以訪問virtual DOM了
  • componentWillReceiveProps:初次渲染不被調用,只有當props屬性值有變化才調用
  • componentWillUnmount:從virutal DOM分離的時候調用

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Object.prototype.exist = function(){ if(typeof this !='undefined' && this.length>=1){ return true; } return false; }; 不解釋 Object.prototype.exist = fun ...
  • 問題 在node項目中,往往需要安裝一些依賴的包,通常我們採取全局安裝的方式,來減少一些包重覆安裝帶來的煩惱。 但是全局安裝後出現無法使用的情況,可能是你NODE_PATH沒有設置或者不正確造成的。 解決方案 那麼,什麼是NODE_PATH呢? NODE_PATH是node為模塊提供尋找路徑的一個環 ...
  • 在使用JQuery的Ajax從伺服器請求數據或者向伺服器發送數據時常常會遇到跨域無法請求的錯誤,常用的解決辦法就是在Ajax中使用JSONP。基於安全性考慮,瀏覽器會存在同源策略,然而<script/>標簽卻具有跨域訪問數據的能力,這就是JSONP工作的基本原理。有關同源策略以及什麼是JSONP,可 ...
  • 最近在研究頁面渲染及web動畫的性能問題,以及拜讀《CSS SECRET》(CSS揭秘)這本大作。 本文主要想談談頁面優化之滾動優化。 主要內容包括了為何需要優化滾動事件,滾動與頁面渲染的關係,節流與防抖,pointer-events:none 優化滾動。因為本文涉及了很多很多基礎,是我自己學習記錄 ...
  • HTML5是HTML標準的下一個版本。越來越多的程式員開始HTML5來構建網站。如果你同時使用HTML4和HTML5的話,你會發現用HTML5從頭構建,比從HTML4遷移到HTML5要方便很多。雖然HTML5沒有完全顛覆HTML4,它們還是有很多相似之處,但是它們也有一些關鍵的不同。本文就列出了它們 ...
  • 項目中關於ajax jsonp的使用,出現了問題:可以成功獲得請求結果,但沒有執行success方法總算搞定了,記錄一下 function TestAjax() { $.ajax({ type : "get", async : false, url : "ajaxHandler.ashx", //實 ...
  • CSS為一些特殊效果準備了特定的工具,我們稱之為“偽類”。其中有幾項是我們經常用到的,下麵我們就詳細介紹一下經常用於定義鏈接樣式的四個偽類,它們分別是: 1 :link 2 :visited 3 :hover 4 :active 因為我們要定義鏈接樣式,所以其中必不可少的就是超級鏈接中的錨標簽--a ...
  • 一、原型鏈 利用 Person.prototype = new Animal("Human") 實現繼承; static式繼承、能繼承Animal.prototype、不可多重繼承; 二、借用構造函數 對象冒充、apply、call三個方法的原理都是使用Person的this調用Animal; pr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...