本文是在閱讀學習了官方的React Tutorial之后的整理,一個靜態的評論區組件。
所以內容,和React官網一模一樣,可查看官網源代碼。
開始使用React
首先從官方獲取React.js,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="build/react.js"></script> <script src="build/react-dom.js"></script> <script src="build/browser.min.js"></script> <script src="build/jquery.min.js"></script> <script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script> </head> <body> <div id="content"></div> <script type="text/babel" src="./scripts/example.js"></script> </body> </html>
你的第一個組件
React 中都是關於模塊化、可組裝的組件。以我們的評論框為例,我們將有如下的組件結構:
- CommentBox - CommentList -Comment - CommentForm
通過React.createClass()可以一個React組件,我們可以像這樣定義我們的CommentBox,並通過ReactDOM.render()方法可以讓我們在指定的容器中將React元素渲染為一個DOM組件
var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1>
<CommentList />
<CommentForm /></div> ); } }); ReactDOM.render( <CommentBox />, document.getElementById('content') );
注意原生的HTML元素以小寫開頭,而制定的 React 類以大寫開頭。
從這個例子也可以看出一個組件可以包含子組件,組件之間是可以組合的(Composing),並呈現一個樹形結構,也可以說render方法中的的 CommentBox代表的是組件樹的根元素。那么接下來我們來創建CommentList和CommentForm這兩個子組件。
var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> Hello, world! I am a CommentList. </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } });
首先是CommentList組件,這個組件是用來呈現評論列表的,根據開始我們設計的組件結構樹,這個組件應該是包含許多Comment子組件的,
var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {this.props.children} </div> ); } });
既然我們已經定義了 Comment
組件,我們將要傳遞作者名和評論文字給它。這允許我們為每個評論重用相同的代碼。現在讓我們在我們的 CommentList
里添加一些評論。
var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="Pete Hunt">This is one comment</Comment> <Comment author="Jordan Walke">This is *another* comment</Comment> </div> ); } });
注意,我們已經從 CommentList
組件傳遞了一些數據到 Comment
組件。例如,我們傳遞了 Pete Hunt (通過屬性)和 This is one comment (通過 XML-風格的子節點)給第一個 Comment
。如上面提到的那樣, Comment
組件將會通過 this.props.author
和 this.props.children
訪問 這些 '屬性'。
添加 Markdown #
Markdown 是一種簡單的內聯格式化你的文字的方法。例如,用星號包圍文本將會使其強調突出。
在本教程中我們使用第三方庫 remarkable,它接受 Markdown 文本並且轉換為原始的 HTML。我們已經在初始的頁面標記里包含了這個庫,所以我們可以直接開始使用它,讓我們轉換評論文本為 Markdown 並輸出它:
var Comment = React.createClass({ render: function() { var md = new Remarkable(); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {md.render(this.props.children.toString())} </div> ); } });
我們在這里唯一做的就是調用 remarkable 庫。我們需要把 從 React 的包裹文本來的 this.props.children
轉換成 remarkable 能理解的原始字符串,所以我們顯示地調用了toString()
。
但是這里有一個問題!我們渲染的評論在瀏覽器里看起來像這樣: "<p>
This is <em>
another</em>
comment</p>
" 。我們想讓這些標簽真正地渲染為 HTML。
那是 React 在保護你免受 XSS 攻擊。有一個方法解決這個問題,但是框架會警告你別使用這種方法:
var Comment = React.createClass({ rawMarkup: function() { var md = new Remarkable(); var rawMarkup = md.render(this.props.children.toString()); return { __html: rawMarkup }; }, render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={this.rawMarkup()} /> </div> ); } });
這是一個特殊的 API,故意讓插入原始的 HTML 變得困難,但是對於 remarkable 我們將利用這個后門。
記住: 使用這個功能你會依賴於 remarkable 是安全的。
那么,假設我們已經獲取到評論數據了:
var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ];
我們需要把數據傳遞給CommentList組件才能讓它去呈現,那么如何傳遞呢?我們可以通過this.props來訪問組件標簽上的屬性,比如我們在CommentBox組件的代碼中做如下修改:
var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.props.data} /> <CommentForm /> </div> ); } }); ReactDOM.render( <CommentBox data={data} />, document.getElementById('content') );
然現在數據在 CommentList
中可用了,讓我們動態地渲染評論:
var CommentList = React.createClass({ render: function() { var commentNodes = this.props.data.map(function(comment) { return ( <Comment author={comment.author} key={comment.id}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } });
好了,接下來我們的CommentList算是完成了,我們需要加上CommentForm組件讓我們可以提交評論:
var CommentForm = React.createClass({ getInitialState: function() { return {author: '', text: ''}; }, handleAuthorChange: function(e) { this.setState({author: e.target.value}); }, 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 (!text || !author) { return; } this.props.onCommentSubmit({author: author, text: text}); // TODO: send request to the server this.setState({author: '', text: ''});//清空文本框里內容 }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange}/> <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } });
我們發現到現在為止,我們的頁面是靜態的,但我們希望可以在成功提交了評論后可以立刻在評論列表中看到自己的評論,並可以每隔一段時間獲取最新的評論,也就是說我們希望我們的CommentBox可以動態地改變狀態。
var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, onCommentSubmit: function(comment) { data.push(comment); var self = this; setTimeout(function() { // 動態更新state self.setState({data: data}); }, 500); }, // 當組件render完成后自動被調用 componentDidMount: function() { var self = this; setTimeout(function() { // 動態更新state self.setState({data: data}); }, 2000); }, render:function(){ return ( <div className ="commentBox"> <h1>評論列表</h1> <CommentList data={this.props.data}/> <CommentForm onCommentSubmit={this.onCommentSubmit} /> </div> ) } });
以上是靜態加載評論區,這個的react代碼如下
var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ]; var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, onCommentSubmit: function(comment) { data.push(comment); var self = this; setTimeout(function() { // 動態更新state self.setState({data: data}); }, 500); }, // 當組件render完成后自動被調用 componentDidMount: function() { var self = this; setTimeout(function() { // 動態更新state self.setState({data: data}); }, 2000); }, render:function(){ return ( <div className ="commentBox"> <h1>評論列表</h1> <CommentList data={this.props.data}/> <CommentForm onCommentSubmit={this.onCommentSubmit} /> </div> ) } }); var CommentList = React.createClass({ render: function() { var commentNodes = this.props.data.map(function(comment) { return ( <Comment author={comment.author} key={comment.id}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ getInitialState: function() { return {author: '', text: ''}; }, handleAuthorChange: function(e) { this.setState({author: e.target.value}); }, 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 (!text || !author) { return; } this.props.onCommentSubmit({author: author, text: text}); // TODO: send request to the server this.setState({author: '', text: ''});//清空文本框里內容 }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange}/> <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } }); var Comment =React.createClass({ rawMarkup: function() { var md = new Remarkable(); var rawMarkup = md.render(this.props.children.toString()); return { __html: rawMarkup }; }, render:function(){ return( <div className="comment"> <h2>{this.props.author}</h2> <span dangerouslySetInnerHTML={this.rawMarkup()} /> </div> ) } }); ReactDOM.render( <CommentBox data={data}/>, document.getElementById('content') );
原文章:http://www.open-open.com/lib/view/open1424570502236.html