利用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

相关文章
相关标签/搜索