[关闭]
@brizer 2016-01-28T20:35:08.000000Z 字数 7795 阅读 968

入门教程


前言

随着入门教程做一个评论组件出来。


首先是官网提供的源码地址

首先新建public/index.html:

  1. <!-- index.html -->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="utf-8" />
  6. <title>React Tutorial</title>
  7. <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react.js"></script>
  8. <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react-dom.js"></script>
  9. <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  10. <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  11. </head>
  12. <body>
  13. <div id="content"></div>
  14. <script type="text/babel" src="scripts/example.js"></script>
  15. <script type="text/babel">
  16. // 如果需要自己加代码,可以将上面的example.js注释掉
  17. </script>
  18. </body>
  19. </html>

这里引用jquery不是说明react必须依赖jquery。


设计组件结构

我们首先设计组件的结构:

  1. CommentBox
  2. CommentList
  3. Comment
  4. CommentForm

定义组件

我们先定义一个简单的CommentBox:

  1. <div id="content"></div>
  2. <script type="text/babel">
  3. // 如果需要自己加代码,可以将上面的example.js注释掉
  4. var CommentBox = React.createClass({
  5. render: function(){
  6. return (
  7. <div className="commentBox">
  8. Hello,world!I am a CommentBox.
  9. </div>
  10. );
  11. }
  12. });
  13. React.render(
  14. <CommentBox />,
  15. document.getElementById("content")
  16. );
  17. </script>

效果如下:


我们使用的JSX语法在以后会详解。
在上面的代码中,我们通过React.createClass()来创建一个新的组件。其中最重要的方法是render,该方法返回一颗React组件树,这棵树最终将会演变成HTML。

接下来我们定义CommentList,CommentForm。

  1. //CommentList组件
  2. var CommentList = React.createClass({
  3. render:function(){
  4. return (
  5. <div className="commentList">
  6. Hello,world!I am a CommentList.
  7. </div>
  8. );
  9. }
  10. });
  11. //CommentForm组件
  12. var CommentForm = React.createClass({
  13. render:function(){
  14. return (
  15. <div className="commentForm">
  16. Hello.world!I am a CommentForm.
  17. </div>
  18. );
  19. }
  20. });

组装

我们把上面定义的两个组件组装到CommentBox中:

  1. //CommentBox组件
  2. var CommentBox = React.createClass({
  3. render: function(){
  4. return (
  5. <div className="commentBox">
  6. <h1>Comments</h1>
  7. <CommentList />
  8. <CommentForm />
  9. </div>
  10. );
  11. }
  12. });

效果如下:

组件拼接成功。


props

我们创建Comment组件,该组件依赖于从父级传入的数据。我们可以通过this.props访问到这些数据:

  1. //Comment组件
  2. var Comment = React.createClass({
  3. render:function(){
  4. return (
  5. <div className="comment">
  6. <h2 className="commentAuthor">
  7. {this.props.author}
  8. </h2>
  9. {this.props.children}
  10. </div>
  11. );
  12. }
  13. });

接下来我们就可以对每一个独立的评论重用相同的代码了,先添加一些评论到CommentList:

  1. //CommentList组件
  2. var CommentList = React.createClass({
  3. render:function(){
  4. return (
  5. <div className="commentList">
  6. <Comment author="刘放">这是刘放的评论</Comment>
  7. <Comment author="tyq">这是 *tyq* 的评论</Comment>
  8. </div>
  9. );
  10. }
  11. });

得到效果如下:

其中我们通过this.props.author和this.props.children 来访问属性。


添加markdown语法格式

需要用到第三方库:

  1. <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>

接下来进行转换输出:

  1. //Comment组件
  2. var Comment = React.createClass({
  3. render:function(){
  4. return (
  5. <div className="comment">
  6. <h2 className="commentAuthor">
  7. {this.props.author}
  8. </h2>
  9. {marked(this.props.children.toString())}
  10. </div>
  11. );
  12. }
  13. });

效果如下:

可以看到结果并不是我们想要的,这样因为React在保护应用免受XSS攻击。我们进入如下修改:

  1. //Comment组件
  2. var Comment = React.createClass({
  3. rawMarkup:function(){
  4. var rawMarkup = marked(this.props.children.toString(),{sanitize:true});
  5. return { __html:rawMarkup };
  6. },
  7. render:function(){
  8. return (
  9. <div className="comment">
  10. <h2 className="commentAuthor">
  11. {this.props.author}
  12. </h2>
  13. <span dangerouslySetIneerHTML={this.rawMarkup()}/>
  14. </div>
  15. );
  16. }
  17. });

我们传入sanitize:true,告诉marked转义掉评论文本中的HTML标签而不是直接原封不动地返回这些标签。


数据引入

之前我们使用的是静态数据,现在我们模拟从后端传来json格式数据:

  1. //模拟评论数据
  2. var data = [
  3. {author:"liufang",text:"good boy"},
  4. {author:"tyq",text:"good girl"}
  5. ];

接下来我们在渲染时,将data绑定到属性:

  1. ReactDOM.render(
  2. <CommentBox data={data}/>,
  3. document.getElementById("content")
  4. );

CommentBox组件汇总将data属性传递下去:

  1. //CommentBox组件
  2. var CommentBox = React.createClass({
  3. render: function() {
  4. return (
  5. <div className="commentBox">
  6. <h1>Comments</h1>
  7. <CommentList data={this.props.data} />
  8. <CommentForm />
  9. </div>
  10. );
  11. }
  12. });

最后在CommentList中进行属性对于赋值:

  1. //CommentList组件
  2. var CommentList = React.createClass({
  3. render: function() {
  4. var commentNodes = this.props.data.map(function (comment) {
  5. return (
  6. <Comment key={comment.author} author={comment.author}>
  7. {comment.text}
  8. </Comment>
  9. );
  10. });
  11. return (
  12. <div className="commentList">
  13. {commentNodes}
  14. </div>
  15. );
  16. }
  17. });

通过map将data遍历,取author和text属性对应赋值。
效果如下


响应状态变化

前面提到,组件根据props渲染自己,props是从父组件传递过来的不变的属性列表。为了实现交互,我们给组件引入了可变的statethis.state是组件私有的,可以通过调用this.setState()来改变,当state更新后,组件就会重新渲染。

我们先将数据存入data.json:

  1. [
  2. {"author":"liufang","text":"good boy"},
  3. {"author":"tyq","text":"good girl"}
  4. ]

然后在渲染时通过url:

  1. ReactDOM.render(
  2. <CommentBox url="./data.json"/>,
  3. document.getElementById("content")
  4. );

将CommentBox组件改成通过ajax获取:

  1. //CommentBox组件
  2. var CommentBox = React.createClass({
  3. //初始化组件的state设置,在组件生命中仅执行一次
  4. getInitialState:function(){
  5. return {data:[]};
  6. },
  7. //组件渲染时,React自动调用的方法
  8. componentDidMount:function(){
  9. $.ajax({
  10. url:this.props.url,
  11. dataType:'json',
  12. cache:false,
  13. success:function(data){
  14. //关键,将数据设置到视图
  15. this.setState({data:data});
  16. }.bind(this),
  17. error:function(xhr,status,err){
  18. console.error(this.props.url,status,err.toString());
  19. }.bind(this)
  20. });
  21. },
  22. render: function() {
  23. return (
  24. <div className="commentBox">
  25. <h1>Comments</h1>
  26. <CommentList data={this.state.data} />
  27. <CommentForm />
  28. </div>
  29. );
  30. }
  31. });

上面的componentDidMount是一个组件渲染的时候被React自动调用的方法。其中的关键点就是调用this.setState(),在服务器数据改变时,对数据进行改变。


实时数据

上面就可以得到正常的效果了。如果我们需要实现实时更新的话。需要进行以下改变,从而进行简单的轮询。
首先,在渲染时传入轮询时间:

  1. ReactDOM.render(
  2. <CommentBox url="./data.json" pollInterval={2000} />,
  3. document.getElementById("content")
  4. );

然后对CommentBox进行改装,进行轮询:

  1. //CommentBox组件
  2. var CommentBox = React.createClass({
  3. //初始化组件的state设置,在组件生命中仅执行一次
  4. getInitialState:function(){
  5. return {data:[]};
  6. },
  7. //请求服务器函数
  8. loadCommentsFromServer:function(){
  9. $.ajax({
  10. url:this.props.url,
  11. dataType:'json',
  12. cache:false,
  13. success:function(data){
  14. this.setState({data:data});
  15. }.bind(this),
  16. error:function(xhr,status,err){
  17. console.error(this.props.url,status,err.toString());
  18. }.bind(this)
  19. });
  20. },
  21. //组件渲染时,React自动调用的方法
  22. //进行轮询调用请求
  23. componentDidMount:function(){
  24. this.loadCommentsFromServer();
  25. setInterval(this.loadCommentsFromServer,this.props.pollInterval);
  26. },
  27. render: function() {
  28. return (
  29. <div className="commentBox">
  30. <h1>Comments</h1>
  31. <CommentList data={this.state.data} />
  32. <CommentForm />
  33. </div>
  34. );
  35. }
  36. });

这样就可以达到轮询的效果。


添加评论

前面的CommentList和Comment组件功能都基本完成了。接下来就是CommentForm组件,其功能是将评论的名字和内容保存到服务器。

  1. //CommentForm组件
  2. var CommentForm = React.createClass({
  3. handleSubmit:function(e){
  4. e.preventDefault();
  5. var author = this.refs.author.value.trim();
  6. var text = this.refs.text.value.trim();
  7. if(!text||!author){
  8. return;
  9. }
  10. //发送到服务器
  11. //清空表单
  12. this.refs.author.value='';
  13. this.refs.text.value='';
  14. return;
  15. },
  16. render:function(){
  17. return (
  18. <form className="commentForm" onSubmit={this.handleSubmit}>
  19. <input type="text" ref="author" placeholder="name" />
  20. <input type="text" ref="text" placeholder="say something" />
  21. <input type="submit" value="Post" />
  22. </form>
  23. );
  24. }
  25. });

效果如下:


刷新评论栏

当用户提交评论时,我们需要刷新评论列表来加进这条新评论。在CommentBox组件中完成这个逻辑,因为该组件拥有代表评论列表的state。

我们需要从子组件传数据到它的父组件。我们在父组件的render方法中这样做:传递一个新的回调函数handleCommentSubmit到子组件,绑定它到子组件的onCommentSubmit事件上。无论事件什么时候触发,回调函数都会被调用。

  1. //CommentBox组件
  2. var CommentBox = React.createClass({
  3. //初始化组件的state设置,在组件生命中仅执行一次
  4. getInitialState:function(){
  5. return {data:[]};
  6. },
  7. //请求服务器函数
  8. loadCommentsFromServer:function(){
  9. $.ajax({
  10. url:this.props.url,
  11. dataType:'json',
  12. cache:false,
  13. success:function(data){
  14. this.setState({data:data});
  15. }.bind(this),
  16. error:function(xhr,status,err){
  17. console.error(this.props.url,status,err.toString());
  18. }.bind(this)
  19. });
  20. },
  21. //组件渲染时,React自动调用的方法
  22. //进行轮询调用请求
  23. componentDidMount:function(){
  24. this.loadCommentsFromServer();
  25. setInterval(this.loadCommentsFromServer,this.props.pollInterval);
  26. },
  27. //绑定到子组件的回调函数
  28. handleCommentSubmit:function(comment){
  29. //提交到服务器并刷新列表
  30. },
  31. render: function() {
  32. return (
  33. <div className="commentBox">
  34. <h1>Comments</h1>
  35. <CommentList data={this.state.data} />
  36. //CommentForm表单提交事件
  37. <CommentForm onCommentSubmit={this.handleCommentSubmit} />
  38. </div>
  39. );
  40. }
  41. });

当用户提交表单时,在CommentForm中调用这个回调函数:

  1. //CommentForm组件
  2. var CommentForm = React.createClass({
  3. handleSubmit:function(e){
  4. e.preventDefault();
  5. var author = this.refs.author.value.trim();
  6. var text = this.refs.text.value.trim();
  7. if(!text||!author){
  8. return;
  9. }
  10. //发送到服务器
  11. //清空表单
  12. //提交表单时调用回调函数
  13. this.props.onCommentSubmit({author:author,text:text});
  14. this.refs.author.value='';
  15. this.refs.text.value='';
  16. return;
  17. },
  18. render:function(){
  19. return (
  20. <form className="commentForm" onSubmit={this.handleSubmit}>
  21. <input type="text" ref="author" placeholder="name" />
  22. <input type="text" ref="text" placeholder="say something" />
  23. <input type="submit" value="Post" />
  24. </form>
  25. );
  26. }
  27. });

剩下的就是将数据提交到服务器上去了。


感悟

终于把入门demo给做完了,对react的组件化开发大概也有了一定的了解。个人觉得入门还是比较简单。
下一次详细学习JSX语法吧。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注