最近在學習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> </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之類的其餘框架,等研究出來單獨寫篇文章吧