利用React寫一個評論區組件

本文是在閱讀學習了官方的React Tutorial以後的整理,一個靜態的評論區組件。html

因此內容,和React官網如出一轍,可查看官網源代碼。react

開始使用React

首先從官方獲取React.js,jquery

<!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 中都是關於模塊化、可組裝的組件。以咱們的評論框爲例,咱們將有以下的組件結構:git

 
- CommentBox
    - CommentList
        -Comment
    - CommentForm

經過React.createClass()能夠一個React組件,咱們能夠像這樣定義咱們的CommentBox,並經過ReactDOM.render()方法可讓咱們在指定的容器中將React元素渲染爲一個DOM組件github

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
         <h1>Comments</h1>  
      <CommentList />
      <CommentForm />
</div> ); } }); ReactDOM.render( <CommentBox />, document.getElementById('content') );

注意原生的HTML元素以小寫開頭,而制定的 React 類以大寫開頭。npm

從這個例子也能夠看出一個組件能夠包含子組件,組件之間是能夠組合的(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 裏添加一些評論。babel

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 #

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

相關文章
相關標籤/搜索