學習鏈接:http://reactjs.cn/react/docs/tutorial-zh-CN.html
實現功能:主要分兩個部分:1、評論列表的展示 2、評論框的輸入提交
一、組件
1、拆分組件
一個大容器CommentBox中包含CommetList和CommetForm,CommetList中又包含多個Commet組件
2、CommentBox組件
var CommentBox = React.createClass({ render: function(){
return(
<div>
<CommentList />
<CommentForm />
</div>
)
}
})
ReactDOM.render({
<CommetBox />,
document.getElementById('content')
})
//首先在CommentBox中添加兩個組件,然后將CommetBox渲染到頁面上
- React組件必須用大寫字母開頭,且標簽必須閉合,通過return函數返回的標簽也必須是閉合的。比如我將<CommentList/>和<CommentForm/>外面的div去掉,就會報錯
- React.createClass 是ES5形式的定義組件;后面又有了React.Component ,ES6形式的定義組件。(React定義組件的方法http://www.cnblogs.com/wonyun/p/5930333.html)
- ReactDOM.render({element, container, callback})渲染組件的方法,接收三個參數element 要渲染的組件,container渲染的組件要插入在DOM中的位置,callback回調函數,可選參數,傳入時會在組件渲染完成后調用
- render React生命周期中的初始化階段的一個函數,用來組裝組件的html結構,必須要有返回值,返回的也可以是null 或者false
3、CommentList組件
var CommetList= React.createClass({ render: function(){ return( <div> //包含多個comment組件 <Comment /> <Comment /> </div> ) } })
4、Comment組件
var Comment = React.createClass({
render: function(){ return( <div> <h3>"this is author"</h3> //展示作者
<div>"this is comment text"</div> //展示評論 </div> ) } })
5、CommentForm組件
var CommentForm = React.createClass({ render: function(){ return(
<form> <input type='text' placeholder='enter your name'/>
<input type='text' placeholder='say something ...'/>
<input type='submit' value='submit'/>
</form> ) } })
二、數據
1、簡介
React父子組件數據的傳遞可使用props和state。props屬性是組件與生俱來的不可以由組件自己修改,state狀態是事物自己的,可不斷變化。主要區分是組件在運行時需要修改的是state,此外所有的數據都可以是props
屬性 | 狀態 | |
是否能從父組件獲取初始值 | T | F |
是否由父組件修改 | T | F |
能否在組件內部設置默認值 | T | T |
能否在組件內部修改 | F | T |
能否設置子組件的初始值 | T | F |
能否修改子組件的值 | T | F |
(1)、this.props 用來訪問從父組件傳進來的數據
(2)、this.state 用來訪問動態更新的數據
(3)、this.setState() 將服務器獲取的數據更新到狀態中(更新CommetList中的數據)
(4)、父子組件之間的數據通信,父組件通過this.props將數據傳遞給子組件;子組件通過委托(delegate)即事件處理函數與父組件通信,子組件觸發函數,父組件處理。
2、獲取、更新數據
ReactDOM.render(
<CommetBox url='/api/comments', pollInterval={2000}>, //這個請求地址是在server中設置好了,
document.getElementById('content')
)
var CommentBox = React.createClass({
loadCommentsFromServer: function(){
$.ajax({
url: this.props.url, //通過this.props獲取父組件中的屬性
dataType: 'json',
cache: false,
success: function(data){
this.setState({data:data}) //動態更新的關鍵是通過this.setState()設置狀態
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
})
},
getInitialState:function(){
return {data:[]}
},
componentDidMount: function(){
this.loadCommentsFromServer(); //這里通過設置定時器實時刷新數據,為了避免剛開始數據要在間隔時間后才出來的情況,所以先調用一次獲取數據
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function(){
return(
<div>
<CommentList data={this.state.data} />
<CommentForm />
</div>
)
}
})
var CommentList = React.creatClass({
render: function(){
var commnetNodes = this.props.data.map(function(comment){ //data的數據結構[ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ]
return(
<Comment key={comment.id} author={comment.author}>
{commnet.text}
</Comment>
)
})
return(
<div>
{commentNodes}
</div>
)
}
})
var Comment = React.createClass({
return(
<div>
<h3>
{this.props.author}
</h3>
<p>
{this.children.text.toString()}
</p>
</div>
)
})
涉及到的生命周期:
(1)getInitialState 生命周期初始化階段,初始化每個實例特有的狀態,在生命周期里只執行一次,必須返回一個對象或者null
(2)componentDidMount 生命周期初始化階段,在成功render並渲染完真實的DOM后react自動調用的方法,此時可以修改DOM。如果要在渲染后對DOM操作就是在這個階段里。
三、事件
子組件通過事件與父組件通信,子組件觸發,父組件處理。
1、添加評論,綁定事件
基本的操作在子組件CommentForm中完成
var CommentForm = React.createClass({ getInitialState:function(){ return({author:'',text:''}) }, handleAuthorChange: function(e){ this.setState({author: e.target.value}) //通過this.setState()保證輸入實時更新狀態 }, handleTextChange: function(e){ this.setState({text: e.target.value}) }, handleSubmit: function(e){ //提交事件,清空表單 e.preventDefault(); //阻止提交表單的默認行為 var author = this.state.author.trim(); var text = this.state.text.trim(); if (!author || !text) { return } this.setState({author:'',text:''}) }, render:function(){ return( <form onSubmit={this.handleSubmit}> //提交表單 <input type='text' value={this.state.author} placeholder='your name' onChange = {this.handleAuthorChange} //綁定事件 /> <input type='text' value={this.state.text} placeholder='enter something' onChange = {this.handleTextChange} //綁定事件 /> <input type='submit' value='提交' /> </form> ) } })
2、提交更新評論 子組件傳遞數據給父組件
提交評論時需要刷新評論列表來包含這條評論。發送請求及刷新評論的操作在CommentBox(即父組件)中完成,原因是:CommentBox中有評論列表的狀態。現在需要把CommentForm(子組件)中的數據傳遞到CommentBox(父組件)中,子組件通過事件與父組件通信。所以在父組件中傳遞一個回調函數(handleCommetSubmit)到子組件中,子組件綁定這個函數傳值即可,這樣只要子組件CommentForm中的事件被觸發,父組件CommentBox中的回調函數handCommentSubmit就會被調用。
//CommentBox中
handleCommentSubmit: function(comment){ $.ajax({ url:this.props.url, dataType:'json', type:'POST', data: comment, success: function(data){ this.setState({data:data}) }.bind(this), error: function(xhr, status, err){ this.setState({data: comments}); console.log(this.props.url, status, err.toString()) }.bind(this) })
render: function(){
return(
<div>
<CommentList data={this.state.data}/>
<CommentForm onCommentSubmit={this.handleCommentSubmit}/> //傳遞回調函數給子組件
</div>
)
}
//CommentForm中
handleSubmit: function(e){
e.preventDefault();
var author = this.state.author.trim();
var text = this.state.text.trim();
if (!author || !text) {
return
}
this.props.onCommentSubmit({author:author,text:text}) //綁定回調函數,則handleSubmit事件一觸發,回調函數就會被調用
this.setState({author:'',text:''})
},
四、優化
1、更新太慢要等請求完成后頁面才會展示新的評論,手動添加新評論到列表中讓體驗更快一些
handleCommentSubmit: function(comment) { var comments = this.state.data; comment.id = Date.now(); var newComments = comments.concat([comment]);this.setState({data: newComments}); $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { this.setState({data: comments}); console.error(this.props.url, status, err.toString()); }.bind(this) }); }
2、插入的文本中如果有HTML標簽,我們是默認展示成輸入的樣子的,如點<a href='.....'>這里</a>可以跳轉哦。如果我們想要把這種樣子的評論真正的渲染成HTML,可以用到dangerouslySetInnerHTML
<span dangerouslySetInnerHTML={{ __html: this.props.children.toString()}}/>