ReactJS組件之間通訊

最近在學習react.js,不得不說第一次接觸組件化開發很神奇,固然也很不習慣。
react的思想仍是蠻獨特的,固然圍繞react的一系列自動化工具也是讓我感受亞歷山大
今天總結一下react組件之間的通訊,權當是本身的學習筆記:html

reactJs中數據流向的的特色是:單項數據流react

react組件之間的組合不知道爲何給我一種數據結構當中樹的感受,數據就是從根節點(頂端或其餘子樹的頂端)「流」下來,大概就是這個樣子:
圖片描述json

好比這是一個組件樹,數據就能夠從main組件流到jumbotron組件、queationList組件、form組件,相似的queation組件的數據也能夠流到下邊的question組件裏邊。bootstrap

可是很遺憾,這個從上到下的數據流動,只能解決不多的問題,還有一部分的數據流動就是相似從jumbotron組件到form組件的這樣的兄弟組件的流動形式,或者隔着幾個層級的數據流動,再或者子組件發生了數據的變化,想通知父組件,數據流向從子組件到父組件流,這些問題纔是大多數的開發者須要面臨的問題。
因此這篇筆記總結下基礎的組件通訊:數據結構

數據從父組件到子組件

圖片描述

最簡單的通訊就是父子間的通訊,好比上邊圖上的有個jsonObj從main流進了QueationList
參考代碼:app

//這裏模擬出幾條數據
var jsonObj=[
    {name:"A",question:"從小被人打怎麼辦?",TextArea:"習慣就行了",applaud:35,disagree:1},
    {name:"B",question:"長的太帥被人砍怎麼辦?",TextArea:"食屎啦你",applaud:35,disagree:10},
    {name:"C",question:"由於太胖被人摸怎麼辦?",TextArea:"享受就行了",applaud:35,disagree:45},
    {name:"D",question:"被老師打不開心",TextArea:"用錢打臉",applaud:35,disagree:6},
    {name:"E",question:"不愛洗澡怎麼辦?",TextArea:"打一頓就行了",applaud:35,disagree:9}
]

var QuestionList=React.createClass({
    prepareToRender:function(list){
        var array=[];
        for(var i=0;i<list.length;i++){
            array.push(<Question obj={list[i]}   key={i}/>);
        }
        return array;
    },
    render:function(){
        var array=this.prepareToRender(this.props.jsonObj);
        return <div>{array}</div>;
    }
});
var Main = React.createClass({
    //開始渲染
    render: function () {
        return (
            <div>
                <div className="container col-md-6 col-md-offset-3">
                    <div className="container-fluid">
                        <QuestionList jsonObj={jsonObj}  />
                    </div>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,
    document.getElementById('container')
);

代碼寫的不怎麼規範,可是數據的傳遞就是這樣的:
<QuestionList jsonObj={jsonObj} />
這樣就能夠把父組件的數據帶到子組件裏邊框架

數據從子組件到父組件

理論上來講數據只能是單向的,因此不借助插件數據還真很差從子組件到父組件,一種很簡單的手段是回調函數:
在父組件當中寫個回調函數,而後傳遞到子組件,何時子組件數據變化了,直接調這個回調函數就能夠了。
圖片描述函數

好比如今的jumbotron的按鈕被點擊了,咱們想把被點擊這個事件發給它的父組件也就是main組件,那麼咱們能夠這個作:工具

var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },
    render: function () {
        return (
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>開始體驗
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },
    //開始給子組件一個回調函數,用來作子組件給父組件通訊使用
    buttonResponse:function(windowSatus){
        this.setState({openTheWindow : windowSatus});
    },
    //開始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,
    document.getElementById('container')
);

子組件通知父組件狀態變化就是這樣,就好像是兒子找爸爸要零花錢,零花錢以及給不給都是爸爸說了算的。組件化

兄弟組件之間的通訊

這個其實應該是一個動態應用中最多見的通訊,好比jubotron組件的點擊按鈕,form組件的表單出現:
這就是一個典型的兄弟之間的通訊:
圖片描述

兄弟節點其實能夠就是子父通訊&&父子通訊的疊加
首先按鈕被點擊,子組件通知負組件這個事件,而後父組件把這個消息帶給另外一個子組件
下邊是個點擊按鈕顯示錶單的例子:

/**
 * Created by niuGuangzhe on 2016/9/10.
 */
var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },
    render: function () {
        return (
            <div className="jumbotron">
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>開始體驗
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Form = React.createClass({
    getInitialState:function(){
        return {
            inputTitle:"請輸入標題",
            mainBody:"在此輸入正文"
        };
    },
    //點擊按鈕觸發事件:清除全部已經輸入的文字
    cleanText:function(){
        this.setState({
            inputTitle:"",
            mainBody:""});
    },
    //表單監視事件
    handleChange(name,e) {
        var newState = {};
        console.log(name);
        newState[name] =event.target.value;
        this.setState(newState);
    },
    render: function () {
        return (
            <div style={{display:this.props.openTheWindow?"none":"block"}}>
                <form role="form">
                    <div className="form-group">
                        <label htmlFor="title">標題</label>
                        <input type="text" className="form-control" id="title" name="inputTitle" value={this.state.inputTitle} onChange={this.handleChange.bind(this,"inputTitle")}/>
                    </div>

                    <div className="form-group">
                        <label htmlFor="textArea">正文</label>
                        <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea>
                    </div>
                    <div className="row">

                        <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/>
                        <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/>
                    </div>
                </form>
            </div>
        )
    }
})


var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },
    //開始給子組件一個回調函數,用來作子組件給父組件通訊使用
    buttonResponse:function(windowSatus){
        this.setState({openTheWindow : windowSatus});
    },
    //開始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
                <div className="container col-md-6 col-md-offset-3">
                    <Form openTheWindow={this.state.openTheWindow}/>
                </div>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,
    document.getElementById('container')
);

就是這樣,

其實上邊的代碼是我從以前的沒事幹作的一個單頁面上拿過來改的,爲了避免出現代碼沒法運行的問題,下邊貼出全部代碼:

/**
 * Created by niuGuangzhe on 2016/9/10.
 */
var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },
    render: function () {
        return (
            <div className="jumbotron">
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <h2 className="colorChange">React+bootstrap簡單實例</h2>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <p className="colorChange">上手體驗:第一次嘗試組件化開發</p>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>開始體驗
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Form = React.createClass({
    getInitialState:function(){
        return {
            inputTitle:"請輸入標題",
            mainBody:"在此輸入正文"
        };
    },
    //點擊按鈕觸發事件:清除全部已經輸入的文字
    cleanText:function(){
        this.setState({
            inputTitle:"",
            mainBody:""});
    },
    //表單監視事件
    handleChange(name,e) {
        var newState = {};
        console.log(name);
        newState[name] =event.target.value;
        this.setState(newState);
    },
    render: function () {
        return (
            <div style={{display:this.props.openTheWindow?"none":"block"}}>
                <form role="form">
                    <div className="form-group">
                        <label htmlFor="title">標題</label>
                        <input type="text" className="form-control" id="title" name="inputTitle" value={this.state.inputTitle} onChange={this.handleChange.bind(this,"inputTitle")}/>
                    </div>

                    <div className="form-group">
                        <label htmlFor="textArea">標題</label>
                        <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea>
                    </div>
                    <div className="row">

                        <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/>
                        <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/>
                    </div>
                </form>
            </div>
        )
    },
    //監測重新渲染
    componentDidUpdate:function(){
        console.log("子組件從新渲染;");
    }
})

var Question = React.createClass({
    getInitialState : function(){
        return {
            click:true,
            disClick:true
        };
    },
    numberHandle:function(){
        if(this.state.click===true){
            //奇數次點擊,開始增長數據
            this.props.obj.applaud+=1;
            this.setState({click:false});
        }else{
            //偶數次點擊,減去數據
            this.props.obj.applaud-=1;
            this.setState({click:true});
        }
    },
    decreateHandle:function(){
        if(this.state.disClick===true){
            //奇數次點擊,開始增長數據
            this.props.obj.applaud-=1;
            this.setState({disClick:false});
        }else{
            //偶數次點擊,減去數據
            this.props.obj.applaud+=1;
            this.setState({disClick:true});
        }
    },
    render: function () {
        return (
            <div className="row leaveMe">
                <div className="col-md-2">
                    <div className="col-md-12">
                        <button className="btn col-md-12 " onClick={this.numberHandle}>{this.props.obj.applaud-this.props.obj.disagree}<br/><span
                            className="glyphicon glyphicon-chevron-up"></span></button>
                    </div>
                    <span>&ensp;</span>
                    <div className="col-md-12">
                        <button className="btn col-md-12" onClick={this.decreateHandle}><span
                            className="glyphicon glyphicon-chevron-down"></span>
                        </button>
                    </div>
                </div>
                <div className="col-md-10  bs-callout bs-callout-info">
                    <h4>{this.props.obj.question}</h4>
                    <p>{this.props.obj.TextArea}</p>
                </div>
            </div>
        );
    }
});

var QuestionList=React.createClass({
    prepareToRender:function(list){
        var array=[];
        for(var i=0;i<list.length;i++){
            array.push(<Question obj={list[i]}   key={i}/>);
        }
        return array;
    },
    render:function(){
        var array=this.prepareToRender(this.props.jsonObj);
        return <div>{array}</div>;
    }
});


//這裏模擬出幾條數據
var jsonObj=[
    {name:"A",question:"從小被人打怎麼辦?",TextArea:"習慣就行了",applaud:35,disagree:1},
    {name:"B",question:"長的太帥被人砍怎麼辦?",TextArea:"食屎啦你",applaud:35,disagree:10},
    {name:"C",question:"由於太胖被人摸奶怎麼辦?",TextArea:"享受就行了",applaud:35,disagree:45},
    {name:"D",question:"被老師打不開心",TextArea:"用錢打ta臉",applaud:35,disagree:6},
    {name:"E",question:"不愛洗澡怎麼辦?",TextArea:"打一頓就行了",applaud:35,disagree:9}
]

var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },
    //開始給子組件一個回調函數,用來作子組件給父組件通訊使用
    buttonResponse:function(windowSatus){
        this.setState({openTheWindow : windowSatus});
    },
    //開始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
                <div className="container col-md-6 col-md-offset-3">
                    <Form openTheWindow={this.state.openTheWindow}/>
                    <br/><br/>
                    <div className="container-fluid">
                        <QuestionList jsonObj={jsonObj}  />
                    </div>
                </div>
            </div>
        );
    },
//    執行hook函數:從新渲染完成的時候調這個函數
    componentDidUpdate:function(){
        console.log(this.state.openTheWindow);
    }
});
ReactDOM.render(
    <Main />,
    document.getElementById('container')
);

最後就是一個很重要的問題:就是多層級的據數據傳輸,若是還用這個方式來傳播的話,效率貌似是個大問題,解決辦法看你們的作法目前暫時仍是flux之類的其餘框架,等研究出來單獨寫篇文章吧

相關文章
相關標籤/搜索