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

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


React能夠看作是MVC中的V,關注的是視圖層。React的組件就像Angular的Directive,包括了HTML,CSS,JS以及相關數據等。React的組件被定義在了以"JSX"爲後綴的文件中,這些JSX文件會被最終編譯成Javascript文件。數組



來看一個最基本的寫法:app

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

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

以上,咱們能夠了解到:dom

  • 組件建立: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。


一、React在"virtual DOM"這部分是如何工做的?


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


二、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方法來觸發改變狀態。ui


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 嵌套組件的狀態傳遞this


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


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

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>
        )
    }
});


三、組件的生命週期


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

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分離的時候調用
相關文章
相關標籤/搜索