React JS快速入门教程

页面导航:首页 > 网络编程 > JavaScript > React JS快速入门教程

React JS快速入门教程

来源: 作者: 时间:2016-02-05 11:06 【

在入门教程里,我们会创建一个简单却实用的评论盒子来作为我们的例子,你可以把它放进一个博客什么的。它实际上就是Disqus、LiveFyre、Facebook等实时评论的基础实现。我们要实现的功

 

在入门教程里,我们会创建一个简单却实用的评论盒子来作为我们的例子,你可以把它放进一个博客什么的。它实际上就是Disqus、LiveFyre、Facebook等实时评论的基础实现。
我们要实现的功能有:

  • 浏览所有的评论
  • 提交一个评论的表单
  • 为你自定义的后端提供一个钩子

    此外,还有一些优化特性:

    • 优化评论:在评论保存到服务器前,就在列表中将其显示,这样会感觉更快。
    • 实时更新:当其它用户做出评论后,评论列表就可以得到实时的更新。
    • 支持Markdown格式:用户可以用Markdown格式书写内容。

      第一步

      在教程中,我们直接使用的是CDN上的Javascript框架文件。
      下面,打开任意你喜欢的编辑器,创建一个新的HTML文档:

       
      <script src=http://fb.me/react-0.12.0.js></script> <script src=http://fb.me/JSXTransformer-0.12.0.js></script> <script src=http://code.jquery.com/jquery-1.10.0.min.js></script>
       
      <script type=text/jsx> // Your code here </script>

      此后的教程中,我们都将在这里的script标签内编写JavaScript代码。

      注意
      此处我们将jQuery包含了进来,但目的只是为了方便编写ajax调用。但这不是在React中所必须做。

      你的第一个组件

      React所有的一切都是关于模块化、复合化的组件。就我们的评论功能来说,我们将按照下面的组件结构来实现:

      - CommentBox  - CommentList    - Comment  - CommentForm

      我们先来创建一个CommentBox组件,它一开始只是一个简单的

      :

       

      // tutorial1.jsvar CommentBox = React.createClass({  render: function() {    return (      
      Hello, world! I am a CommentBox.
      ); }});React.render( , document.getElementById('content'));

      JSX 语法

      首先,你注意到的是Javascript代码中的XML化语法。我们实际上可以使用一个预编译器来将此语法糖转换为纯Javascript:

      // tutorial1-raw.jsvar CommentBox = React.createClass({displayName: 'CommentBox',  render: function() {    return (      React.createElement('div', {className: commentBox},        Hello, world! I am a CommentBox.      )    );  }});React.render(  React.createElement(CommentBox, null),  document.getElementById('content'));

      这是一种可选的方式,但实际上可以发现JSX语法要比单纯的Javascript语法要简单。了解更多有关 JSX 语法的内容。

      接下来做什么

      下面我们要创建一个新的React组件,采取的方式是向 React.createClass() 传递一个Javascript对象,为组件添加一些方法。其中最重要的一个方法是 render,它会返回一个React组件树,并最终被渲染成HTML。
      div 标签并不是真正的DOM节点,它们只是React div组件的实例。你可以把它想象成能由React识别并处理的一些标记或一段数据。React是安全的。我们并不生成HTML字符串,所以默认是XSS保护。
      你可以返回一个由你或别人创建的组件树,而不一定要返回基本的HTML。正因如此,React组件可以组合使用的:这是可维护前端的宗旨。
      React.render() 初始化了一个根节点组件,然后启动框架,并将标记注入到一个原生DOM元素中。这个DOM元素由第二个参数指定。

      组建组件

      接着我们创建 CommentListCommentForm 基本骨架,它们同样也是 div。注意,这段代码要放在CommentBox 代码的前面。

      // tutorial2.jsvar CommentList = React.createClass({  render: function() {    return (      
      Hello, world! I am a CommentList.
      ); }}); var CommentForm = React.createClass({ render: function() { return (
      Hello, world! I am a CommentForm.
      ); }});

      下一步,更新 CommentBox 组件的代码,使用新定义的两个朋友:

      // tutorial3.jsvar CommentBox = React.createClass({  render: function() {    return (      

      Comments

      ); }});

      注意我们是如何混合使用HTML标签和自建组件的。HTML组件是规范的React组件,与自定义的组件类似,只是有一个差别:JSX编译器会自动将HTML标签重写为 React.createElement(tagName) ,并且不管其它的事情。这是了避免对全局命名空间的污染。

      组件属性

      我们将创建一个第三方组件 Comment,它负责接收评论者的名字和评论的内容。对于每个单独的评论,我们都可以重用这个组件的代码。首先,我们向 CommentList 添加一些评论。

      // tutorial4.jsvar CommentList = React.createClass({  render: function() {    return (      
      This is one comment This is *another* comment
      ); }});

      注意到,这里我们通过父组件 CommentList 向子组件 Comment 传递了一些数据。比如,我们在一个 Comment中,向其传递了Pete Hunt(通过属性)和一条评论(通过XML格式的子节点)。从父组件向子组件传递的数据被称为props(单词properties的缩写)。

      使用props

      接下来,我们就来创建这个Comment组件。使用porps我们可以读取从 CommentList 传递的数据,并渲染一些标记。

      // tutorial5.jsvar Comment = React.createClass({  render: function() {    return (      

      {this.props.author}

      {this.props.children}
      ); }});

      在JSX中通过用括号括起来的JavaScript表达式,可以将文本或者React组件(可以是一个属性或子元素)放进组件树中。this.props 和嵌套元素 this.props.children 中的关键字props是传递给组件的命名属性。

      添加 Markdowen语法支持

      Markdown文本支持内联样式。例如,用星号围起的文本可以强调显示。
      首先,我们需要向程序中添加第三方的 Showdown 库。这是一个支持Markdown并将其转换为原始HTML代码的JavaScript库。我们需要向head中添加一段script标签(我们已经包含了一些React的库):

       
      <script src=http://fb.me/react-0.12.0.js></script> <script src=http://fb.me/JSXTransformer-0.12.0.js></script> <script src=http://code.jquery.com/jquery-1.10.0.min.js></script> <script src=http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js></script>

      下一步,我们将评论的文本做Markdown转换并输出:

      // tutorial6.jsvar converter = new Showdown.converter();var Comment = React.createClass({  render: function() {    return (      

      {this.props.author}

      {converter.makeHtml(this.props.children.toString())}
      ); }});

      此处,我们增加了对Showdown库的调用。为了将 this.props.children 从React包装了的文本转换成Showdown可以接受的原始字符串,我们显式地调用了 toString()
      但是,这里有一个问题需要解决。我们最后渲染出来的评论内容在中看起来却是这样的形式:

      This is another comment

      。我们想要的是让这些标签都能被渲染为实际的HTML。
      这种处理方式是为了防止XSS攻击。有一种方式可以跳过,但是框架会警告你不要使用这种方式。

       

      // tutorial7.jsvar converter = new Showdown.converter();var Comment = React.createClass({  render: function() {    var rawMarkup = converter.makeHtml(this.props.children.toString());    return (      

      {this.props.author}

      ); }});

      这个特殊的API的目的是让插入原生的HTML代码显得困难,但是为Showdown我们还是利用了这个后门。
      记住:使用这个特征时,你必须确定Showdown是安全的。

      连接数据模型

      目前为止,我们是直接在源代码中插入评论。下面,我们将在评论列表中渲染一段JSON数据。最终,我们将从服务器端获取,但是现在,我们把它直接写在代码中:

      // tutorial8.jsvar data = [  {author: Pete Hunt, text: This is one comment},  {author: Jordan Walke, text: This is *another* comment}];

      我们需要以编写模块的方式将数据data添加进 CommentList.因此,我们修改 CommentBox 以及 React.render() 调用的代码,将data通过props进行传递。

      // tutorial9.jsvar CommentBox = React.createClass({  render: function() {    return (      

      Comments

      ); }}); React.render( , document.getElementById('content'));

      现在,data已经被传递进了 CommentList,那么让我们来动态地呈现评论数据:

      // tutorial10.jsvar CommentList = React.createClass({  render: function() {    var commentNodes = this.props.data.map(function (comment) {      return (                  {comment.text}              );    });    return (      
      {commentNodes}
      ); }});

      就是这样!

      从服务器读取

      下面,我们用从服务器端读取的动态数据来替换硬性编码的数据。我们删除了 data 属性,改为采用 URL 来获取:

      // tutorial11.jsReact.render(  ,  document.getElementById('content'));

      这个组件和之前的组件的不同之处在于它必须预先自行渲染。在从服务器端获得请求应答之前,它没有可用的数据,而这些数据是组件呈现评论所必须的。

      反应state

      到现在为止,所有的组件都只是根据自身的props进行一次性的渲染。props 是不可变的:它们是从父组件传递过来,并且为父组件所有。为了实现交互,我们为组件引入了可变的 statethis.state属于组件的私有成员,并且可以通过调用 this.setState() 进行修改。当state更新之后,组件会立即对其自身进行重新渲染。
      实际上在React代码中,render() 方法被被声明为 this.propsthis.state 的函数,并由框架保证了UI总是与输入保持一致。
      当从服务器取得数据后,就可以对我们的评论数据进行修改。首先,我们向 CommentBox 组件的state添加一个包含评论数据的数组data:

      // tutorial12.jsvar CommentBox = React.createClass({  getInitialState: function() {    return {data: []};  },  render: function() {    return (      

      Comments

      ); }});

      在组件的生命周期中,getInitialState() 只执行一次,它负责对组件的state进行初始化。

      更新state

      在组件创建完毕后,我们还想要从服务器GET到JSON,从而更新state来反映最新的数据。在实际的应用中,我们可能创建的是一个动态的应用。但是,在例子中为了简单,还是使用一个静态的JSON文件:

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

      我们打算使用jQuery对服务器进行异步的访问。
      注意: 由于这是一个AJAX应用,因此你需要在一个web服务器上运行,而不能仍停留在文件。最简单的方式是在应用的目录下运行python -m SimpleHTTPServer

      // tutorial13.jsvar CommentBox = React.createClass({  getInitialState: function() {    return {data: []};  },  componentDidMount: function() {    $.ajax({      url: this.props.url,      dataType: 'json',      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  render: function() {    return (      

      Comments

      ); }});

      这里的componentDidMount是一个在React组件渲染以后将被React调用的方法。动态更新的关键取决于 this.state的调用。在从服务器取得数据以后,我们就使用新数组替换评论组件的旧数据,并且让它动态地改变。这种反应的方式,使得动态更新只是做了小小的改变。此处,我们使用的投票数据很简单,你也可以很容易使用WebSockets或其它技术来获得。

      // tutorial14.jsvar CommentBox = React.createClass({  loadCommentsFromServer: function() {    $.ajax({      url: this.props.url,      dataType: 'json',      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  getInitialState: function() {    return {data: []};  },  componentDidMount: function() {    this.loadCommentsFromServer();    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  },  render: function() {    return (      

      Comments

      ); }}); React.render( , document.getElementById('content')

      此处我们做的仅仅是将AJAX调用放到一个独立的方法中,并且在组件第一次加载和此后每隔两秒调用一次。可以尝试在浏览器中运行一下,并且手动修改 comments.json。可以看到,在两秒内变化就被呈现了出来。

      添加新的评论

      现在,是时候创建一个评论表单了。我们的 CommentForm 组件需要向询问用户他们的名字和评论的内容,并将其发送给服务器进行保存。

      // tutorial15.jsvar CommentForm = React.createClass({  render: function() {    return (      
      ); }});

      让我们来创建与表单的交互。当用户点击submit提交以后,我们需要将表单清空,并将一个请求发送到服务器,然后更新评论列表。那么,首先我们需要监听表单的submit事件,并将其清空。

      // tutorial16.jsvar CommentForm = React.createClass({  handleSubmit: function(e) {    e.preventDefault();    var author = this.refs.author.getDOMNode().value.trim();    var text = this.refs.text.getDOMNode().value.trim();    if (!text || !author) {      return;    }    // TODO: send request to the server    this.refs.author.getDOMNode().value = '';    this.refs.text.getDOMNode().value = '';    return;  },  render: function() {    return (      
      ); }});

      事件Events

      React向组件添加的事件处理函数使用的是驼峰命名规则。我们向表单添加了一个 onSumbit 的处理函数,它负责在输入数据合法的表单提交后,将表单的字段清空。
      在事件处理中,调用 preventDefault 是为了阻止浏览器默认的与表单提交有关的行为。

      Refs

      我们使用 ref 属性向子组件分配了一个名字,并且通过 this.refs对组件进行引用。我们可以在一个组件上调用 getDOMNode 获取一个原生DOM元素。

      在props中定义回调函数

      当用户提交一条评论时,我们还需要对之前的评论列表进行更新,让新的评论显示进来。对于含有与呈现评论有关数据的state的CommentBox 来说,需要定义这样的行为逻辑。
      我们需要从子组件传送数据到它的父组件。我们在父组件的 render 方法中将一个新的回调函数(handleCommentSubmit)传递给子组件,并将其绑定在子组件的 onCommentSubmit 事件上。当事件被触发后,回调函数就会被执行。

      // tutorial17.jsvar CommentBox = React.createClass({  loadCommentsFromServer: function() {    $.ajax({      url: this.props.url,      dataType: 'json',      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  handleCommentSubmit: function(comment) {    // TODO: submit to the server and refresh the list  },  getInitialState: function() {    return {data: []};  },  componentDidMount: function() {    this.loadCommentsFromServer();    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  },  render: function() {    return (      

      Comments

      ); }});

      当用户提交表单的时候,我们就从 CommentForm 调用回调函数。

      // tutorial18.jsvar CommentForm = React.createClass({  handleSubmit: function(e) {    e.preventDefault();    var author = this.refs.author.getDOMNode().value.trim();    var text = this.refs.text.getDOMNode().value.trim();    if (!text || !author) {      return;    }    this.props.onCommentSubmit({author: author, text: text});    this.refs.author.getDOMNode().value = '';    this.refs.text.getDOMNode().value = '';    return;  },  render: function() {    return (      
      ); }});

      现在,回调函数已经定义完毕。我们要做的就是提交新的评论到服务器,并刷新评论列表。

      // tutorial19.jsvar CommentBox = React.createClass({  loadCommentsFromServer: function() {    $.ajax({      url: this.props.url,      dataType: 'json',      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  handleCommentSubmit: function(comment) {    $.ajax({      url: this.props.url,      dataType: 'json',      type: 'POST',      data: comment,      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  getInitialState: function() {    return {data: []};  },  componentDidMount: function() {    this.loadCommentsFromServer();    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  },  render: function() {    return (      

      Comments

      ); }});

      优化:优化更新

      现状我们已经实现了这个应用的所有功能。但是,在从服务器完成请求之前,你必须等待评论在列表中出现。因此,会感觉有点慢。我们可以对它再做一点优化,让它感觉更快一点。

      // tutorial20.jsvar CommentBox = React.createClass({  loadCommentsFromServer: function() {    $.ajax({      url: this.props.url,      dataType: 'json',      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  handleCommentSubmit: function(comment) {    var comments = this.state.data;    var newComments = comments.concat([comment]);    this.setState({data: newComments});    $.ajax({      url: this.props.url,      dataType: 'json',      type: 'POST',      data: comment,      success: function(data) {        this.setState({data: data});      }.bind(this),      error: function(xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  getInitialState: function() {    return {data: []};  },  componentDidMount: function() {    this.loadCommentsFromServer();    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  },  render: function() {    return (      

      Comments

      ); }});

      祝贺你!

      通过一些简单的步骤,你已成功创建了一个评论盒子。你可以了解更多有关为什么使用React 或者深入的学习 API参考。 祝你顺利!

       

       

Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<