• React实践


    React实践(一)

     

    该实践取自官方教程:https://github.com/reactjs/react-tutorial

    主要是自实现的过程以及一些心得体会

    该实践是实现一个评论框。

    • 一个展示所有评论的视图
    • 一个提交评论的表单
    • 与后台的接口hook

    特点:

    • 评论提交之前就先显示在列表中,提高体验
    • 其他用户的评论实时更新
    • 可用markdown格式编写文本

    开始

     下面就是我们的index.html模板文件,看官copy过去吧。之后的所有代码都写在script里面

    复制代码
     1 <!-- index.html -->
     2 <html>
     3   <head>
     4     <title>Hello React</title>
     5     <script src="http://fb.me/react-0.13.0.js"></script>
     6     <script src="http://fb.me/JSXTransformer-0.13.0.js"></script>
     7     <script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
     8   </head>
     9   <body>
    10     <div id="content"></div>
    11     <script type="text/jsx">
    12       // Your code here
    13     </script>
    14   </body>
    15 </html>
    复制代码

    其中jquery不是对React必要的,只是我们想简化ajax的代码

    组件结构

    React是全组件化的,可组装的。我们的组件结构如下:

    - CommentBox
      - CommentList
        - Comment
      - CommentForm

    CommentBox

    让我们先来把最基本的组件构造出来

    复制代码
     1 var CommentBox = React.createClass({
     2   render: function() {
     3     return (
     4       <div className="commentBox">
     5         Hello, world! I am a CommentBox.
     6       </div>
     7     );
     8   }
     9 });
    10 React.render(
    11   <CommentBox />,
    12   document.getElementById('content')
    13 );
    复制代码

    从代码不难看出,也不过是简单的div罢了

    CommentList、CommentForm

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

    这两个组件也不过就是div而已

    那我们根据组件结构,把这两个组件放进CommentBox:

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

    Comment

    组件结构里,现在还剩CommentList里的Comment。我们想在评论中传评论人和评论文本过去。那我们来实现一下:

    复制代码
     1 var CommentList = React.createClass({
     2   render: function() {
     3     return (
     4       <div className="commentList">
     5         <Comment author="Pete Hunt">This is one comment</Comment>
     6         <Comment author="Jordan Walke">This is *another* comment</Comment>
     7       </div>
     8     );
     9   }
    10 });
    复制代码

    我们已经从父组件CommenList传递了一些数据给子组件Comment

    那我们来实现Comment组件,看官应该还记得,我们通过this.props在子组件中获取数据:

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

    其中,this.props.children是任何内嵌的元素。

    而前面说了,我们提供markdown格式的输入,那就修改一下。

    添加Markdown

    这里我们要用到第三方库Showdown,作用是处理Markdown文本且转换成原始HTML。

    我们先添加<script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>到head中

    接着我们修改this.props.children,且添加Showdown的调用

    复制代码
     1 var converter = new Showdown.converter();
     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         {converter.makeHtml(this.props.children.toString())}
    10       </div>
    11     );
    12   }
    13 });
    复制代码

    其中,为了转换成Showdown能处理的原始字符串,所以显示调用了toString()

    但是React为了防止XSS,我们的显示会类似这样,<p>This is<em>another</em> comment</p>

    并没有渲染成真正的HTML

    当然我们这里有一个方法:

    复制代码
     1 var converter = new Showdown.converter();
     2 var Comment = React.createClass({
     3   render: function() {
     4     var rawMarkup = converter.makeHtml(this.props.children.toString());
     5     return (
     6       <div className="comment">
     7         <h2 className="commentAuthor">
     8           {this.props.author}
     9         </h2>
    10         <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
    11       </div>
    12     );
    13   }
    14 });
    复制代码

    注意:框架会警告你别使用这种方法

    接入数据模型

    上面,我们是把数据直接写入React中,实际开发中,数据是来自于数据库的,那我们这里就暂且用hard code的形式写在JSON对象中。

    1 var data = [
    2   {author: "Pete Hunt", text: "This is one comment"},
    3   {author: "Jordan Walke", text: "This is *another* comment"}
    4 ];

    我们需要把数据通过props的形式传到CommentList。而首先就是把数据传入到CommentBox

    这里是React的单向数据流。关于这个,会在之后另开一篇文章来研究下。

    复制代码
     1 var CommentBox = React.createClass({
     2   render: function() {
     3     return (
     4       <div className="commentBox">
     5         <h1>Comments</h1>
     6         <CommentList data={this.props.data} />
     7         <CommentForm />
     8       </div>
     9     );
    10   }
    11 });
    12 
    13 React.render(
    14   <CommentBox data={data} />,
    15   document.getElementById('content')
    16 );
    复制代码

    这时候,CommentList就可以使用数据了。让我们来动态地去渲染评论,而不是之前一条一条地写<Comment >xxx</Comment>

    来看下代码:

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

    就这样了。

    从数据库获取数据

    实际开发中,往往是后台提供了数据接口,而这时候,我们就需要这个接口跟我们上面的实现结合起来了。

    而且,现在的这个组件在请求数据回来之前,是没有数据的。并且,评论是需要更新的。

    我们之前是通过data传给CommentBox,每个组件也只在初始化的时候更新一次。

    props是不可变的,它们从父节点传过来,被父节点所拥有。而为了实现交互,这里就需要用到state,this.state是组件私有的,当state变化的时候,组件会重新渲染自己。

    关于props和state,之后也会写一篇来具体介绍一下。

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

    因为,我们这里没有去实现后台,所以姑且用本地的文件comments.json来返回这个JSON对象,就创建一个comments.json文件放在index.html同目录下,把下面的复制进去:

    // comments.json
    [
      {"author": "Pete Hunt", "text": "This is one comment"},
      {"author": "Jordan Walke", "text": "This is *another* comment"}
    ]

    这里我们用的是JQ的AJAX,下面是修改后的CommentBox:

    复制代码
     1 var CommentBox = React.createClass({
     2   getInitialState: function() {
     3     return {data: []};
     4   },
     5   componentDidMount: function() {
     6     $.ajax({
     7       url: this.props.url,
     8       dataType: 'json',
     9       success: function(data) {
    10         this.setState({data: data});
    11       }.bind(this),
    12       error: function(xhr, status, err) {
    13         console.error(this.props.url, status, err.toString());
    14       }.bind(this)
    15     });
    16   },
    17   render: function() {
    18     return (
    19       <div className="commentBox">
    20         <h1>Comments</h1>
    21         <CommentList data={this.state.data} />
    22         <CommentForm />
    23       </div>
    24     );
    25   }
    26 });
    复制代码

    这里我们给CommentBox添加了一个data数组的state,作为取到的评论的保存。

    组件会在组件构建完后,去取数据,动态更新的要点就是this.setState()

    而我们的评论是实时更新的,即别人如果在数据库里添加了评论,那我们是要实时去检测是否更新了的。

    这里我们就简单的用轮训的方法:

    复制代码
     1 var CommentBox = React.createClass({
     2   loadCommentsFromServer: function() {
     3     $.ajax({
     4       url: this.props.url,
     5       dataType: 'json',
     6       success: function(data) {
     7         this.setState({data: data});
     8       }.bind(this),
     9       error: function(xhr, status, err) {
    10         console.error(this.props.url, status, err.toString());
    11       }.bind(this)
    12     });
    13   },
    14   getInitialState: function() {
    15     return {data: []};
    16   },
    17   componentDidMount: function() {
    18     this.loadCommentsFromServer();
    19     setInterval(this.loadCommentsFromServer, this.props.pollInterval);
    20   },
    21   render: function() {
    22     return (
    23       <div className="commentBox">
    24         <h1>Comments</h1>
    25         <CommentList data={this.state.data} />
    26         <CommentForm />
    27       </div>
    28     );
    29   }
    30 });
    31 
    32 React.render(
    33   <CommentBox url="comments.json" pollInterval={2000} />,
    34   document.getElementById('content')
    35 );
    复制代码

    关于显示的,我们就弄的差不多了。

    接下来是我们的表单提交部分

    添加新评论

    我们的表单要求用户输入评论人和评论内容,当用户提交表单的时候,会把数据提交到服务器,然后保存这条数据。

    复制代码
     1 var CommentForm = React.createClass({
     2   render: function() {
     3     return (
     4       <form className="commentForm">
     5         <input type="text" placeholder="Your name" />
     6         <input type="text" placeholder="Say something..." />
     7         <input type="submit" value="Post" />
     8       </form>
     9     );
    10   }
    11 });
    复制代码

    我们的表单是可交互的,所以这里要添加表单的提交事件,且刷新评论列表。为了更好的体验,在提交完表单之后,表单应该是清空了的。

    复制代码
     1 var CommentForm = React.createClass({
     2   handleSubmit: function(e) {
     3     e.preventDefault();
     4     var author = this.refs.author.getDOMNode().value.trim();
     5     var text = this.refs.text.getDOMNode().value.trim();
     6     if (!text || !author) {
     7       return;
     8     }
     9     // TODO: send request to the server
    10     this.refs.author.getDOMNode().value = '';
    11     this.refs.text.getDOMNode().value = '';
    12     return;
    13   },
    14   render: function() {
    15     return (
    16       <form className="commentForm" onSubmit={this.handleSubmit}>
    17         <input type="text" placeholder="Your name" ref="author" />
    18         <input type="text" placeholder="Say something..." ref="text" />
    19         <input type="submit" value="Post" />
    20       </form>
    21     );
    22   }
    23 });
    复制代码

    其中,

    • 我们利用了ref属性给子组件命名,this.refs引用组件,getDOMNode()获取本地的DOM元素。
    • React使用驼峰命名的方式给组件绑定事件,我们给表单绑定了onSubmit()事件,当数据合法,清空输入框

    当用户提交了表单后,我们需要添加我们的评论到评论列表。上面我们是给了commentBox一个state来保存评论列表。正是因为这样,我们的所有逻辑在commentBox中完成是最合理的。因为我们需要从子组件传回数据给父组件,这里我们把回调函数作为属性传给子组件。

    复制代码
     1 var CommentBox = React.createClass({
     2   loadCommentsFromServer: function() {
     3     $.ajax({
     4       url: this.props.url,
     5       dataType: 'json',
     6       success: function(data) {
     7         this.setState({data: data});
     8       }.bind(this),
     9       error: function(xhr, status, err) {
    10         console.error(this.props.url, status, err.toString());
    11       }.bind(this)
    12     });
    13   },
    14   handleCommentSubmit: function(comment) {
    15     // TODO: submit to the server and refresh the list
    16   },
    17   getInitialState: function() {
    18     return {data: []};
    19   },
    20   componentDidMount: function() {
    21     this.loadCommentsFromServer();
    22     setInterval(this.loadCommentsFromServer, this.props.pollInterval);
    23   },
    24   render: function() {
    25     return (
    26       <div className="commentBox">
    27         <h1>Comments</h1>
    28         <CommentList data={this.state.data} />
    29         <CommentForm onCommentSubmit={this.handleCommentSubmit} />
    30       </div>
    31     );
    32   }
    33 });
    复制代码

    当用户提交表单的时候,调用回调函数:

    复制代码
     1 var CommentForm = React.createClass({
     2   handleSubmit: function(e) {
     3     e.preventDefault();
     4     var author = this.refs.author.getDOMNode().value.trim();
     5     var text = this.refs.text.getDOMNode().value.trim();
     6     if (!text || !author) {
     7       return;
     8     }
     9     this.props.onCommentSubmit({author: author, text: text});
    10     this.refs.author.getDOMNode().value = '';
    11     this.refs.text.getDOMNode().value = '';
    12     return;
    13   },
    14   render: function() {
    15     return (
    16       <form className="commentForm" onSubmit={this.handleSubmit}>
    17         <input type="text" placeholder="Your name" ref="author" />
    18         <input type="text" placeholder="Say something..." ref="text" />
    19         <input type="submit" value="Post" />
    20       </form>
    21     );
    22   }
    23 });
    复制代码

    回调函数等一切都搞定,现在把提交到服务器的代码和刷新评论的代码补上来:

    复制代码
     1 var CommentBox = React.createClass({
     2   loadCommentsFromServer: function() {
     3     $.ajax({
     4       url: this.props.url,
     5       dataType: 'json',
     6       success: function(data) {
     7         this.setState({data: data});
     8       }.bind(this),
     9       error: function(xhr, status, err) {
    10         console.error(this.props.url, status, err.toString());
    11       }.bind(this)
    12     });
    13   },
    14   handleCommentSubmit: function(comment) {
    15     $.ajax({
    16       url: this.props.url,
    17       dataType: 'json',
    18       type: 'POST',
    19       data: comment,
    20       success: function(data) {
    21         this.setState({data: data});
    22       }.bind(this),
    23       error: function(xhr, status, err) {
    24         console.error(this.props.url, status, err.toString());
    25       }.bind(this)
    26     });
    27   },
    28   getInitialState: function() {
    29     return {data: []};
    30   },
    31   componentDidMount: function() {
    32     this.loadCommentsFromServer();
    33     setInterval(this.loadCommentsFromServer, this.props.pollInterval);
    34   },
    35   render: function() {
    36     return (
    37       <div className="commentBox">
    38         <h1>Comments</h1>
    39         <CommentList data={this.state.data} />
    40         <CommentForm onCommentSubmit={this.handleCommentSubmit} />
    41       </div>
    42     );
    43   }
    44 });
    复制代码

    代码基本上都已经完成了。

    还有一个点,我们可以做的,就是为了提高体验,我们可以本地先把用户提交的评论显示出来,之后再异步提交到服务器,让用户觉得应用快快快。

    复制代码
     1 var CommentBox = React.createClass({
     2   loadCommentsFromServer: function() {
     3     $.ajax({
     4       url: this.props.url,
     5       dataType: 'json',
     6       success: function(data) {
     7         this.setState({data: data});
     8       }.bind(this),
     9       error: function(xhr, status, err) {
    10         console.error(this.props.url, status, err.toString());
    11       }.bind(this)
    12     });
    13   },
    14   handleCommentSubmit: function(comment) {
    15     var comments = this.state.data;
    16     var newComments = comments.concat([comment]);
    17     this.setState({data: newComments});
    18     $.ajax({
    19       url: this.props.url,
    20       dataType: 'json',
    21       type: 'POST',
    22       data: comment,
    23       success: function(data) {
    24         this.setState({data: data});
    25       }.bind(this),
    26       error: function(xhr, status, err) {
    27         console.error(this.props.url, status, err.toString());
    28       }.bind(this)
    29     });
    30   },
    31   getInitialState: function() {
    32     return {data: []};
    33   },
    34   componentDidMount: function() {
    35     this.loadCommentsFromServer();
    36     setInterval(this.loadCommentsFromServer, this.props.pollInterval);
    37   },
    38   render: function() {
    39     return (
    40       <div className="commentBox">
    41         <h1>Comments</h1>
    42         <CommentList data={this.state.data} />
    43         <CommentForm onCommentSubmit={this.handleCommentSubmit} />
    44       </div>
    45     );
    46   }
    47 });
    复制代码

    其实就添加了15-17行。

    简单吧~~~~~~~

    这就是React官方提供的最基本的实践~~~~~~
    看到了这里的都是真爱~~~~~~~~~

    晚安~~~~~~~~

     
    分类: React.js
  • 相关阅读:
    确保消息产生前数据库操作已提交
    信息披露和公司简介总结
    1、清空所有,给当前添加/2、清空上一个,给当前添加。
    不能作为判断条件的:
    excel表格 函数功能
    一种ui app写法
    正则中使用变量及数组去重的方法
    鼠标锁定(消失),进入无限滚动状态
    transform 的旋转 ,3d效果,要添加3d效果的父级加上景深perspective。 3d效果的容器加上 transform-style:preserve-3d。
    rem布局,在用户调整手机字体大小/用户调整浏览器字体大小后,布局错乱问题
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4594510.html
Copyright © 2020-2023  润新知