教程

2019-08-14 14:28 更新

我們將構(gòu)建一個(gè)簡(jiǎn)單卻真實(shí)的評(píng)論框,你可以將它放入你的博客,類似disqus、livefyre、facebook提供的實(shí)時(shí)評(píng)論的基礎(chǔ)版。

我們將提供以下內(nèi)容:

  • 一個(gè)展示所有評(píng)論的視圖

  • 一個(gè)提交評(píng)論的表單

  • 用于構(gòu)建自定制后臺(tái)的接口鏈接(hooks)

同時(shí)也包含一些簡(jiǎn)潔的特性:

  • 評(píng)論體驗(yàn)優(yōu)化: 評(píng)論在保存到服務(wù)器之前就展現(xiàn)在評(píng)論列表,因此用戶體驗(yàn)很快。

  • 實(shí)時(shí)更新: 其他用戶的評(píng)論將會(huì)實(shí)時(shí)展示。

  • Markdown格式: 用戶可以使用MarkDown格式來(lái)編輯文本。

想要跳過(guò)所有的內(nèi)容,只查看源代碼?

所有代碼都在GitHub。

運(yùn)行一個(gè)服務(wù)器

雖然它不是入門教程的必需品,但接下來(lái)我們會(huì)添加一個(gè)功能,發(fā)送 POST ing請(qǐng)求到服務(wù)器。如果這是你熟知的事并且你想創(chuàng)建你自己的服務(wù)器,那么就這樣干吧。而對(duì)于另外的一部分人,為了讓你集中精力學(xué)習(xí),而不用擔(dān)憂服務(wù)器端方面,我們已經(jīng)用了以下一系列的語(yǔ)言編寫了簡(jiǎn)單的服務(wù)器代碼 - JavaScript(使用 Node.js),Python和Ruby。所有代碼都在GitHub。你可以查看代碼或者下載 zip 文件來(lái)開始學(xué)習(xí)。

開始使用下載的教程,只需開始編輯 public/index.html 

開始學(xué)習(xí)

在這個(gè)教程里面,我們將使用放在 CDN 上預(yù)構(gòu)建好的 JavaScript 文件。打開你最喜歡的編輯器,創(chuàng)建一個(gè)新的 HTML 文檔:

 <!-- index.html -->
 <html>
  <head>
    <title>Hello React</title>
    <script src="http://fb.me/react- {{site.react_version}}.js" rel="external nofollow" ></script>
    <script src="http://fb.me/JSXTransformer- {{site.react_version}}.js" rel="external nofollow" ></script>
    <script src="http://code.jquery.com/ jquery-1.10.0.min.js" rel="external nofollow" ></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/jsx">
      // Your code here
    </script>
  </body>
 </html>

在本教程其余的部分,我們將在此 script 標(biāo)簽中編寫我們的 JavaScript 代碼。

注意:

因?yàn)槲覀兿牒?jiǎn)化 ajax 請(qǐng)求代碼,所以在這里引入 jQuery,但是它對(duì) React 并不是必須的。

你的第一個(gè)組件

React 中全是模塊化、可組裝的組件。以我們的評(píng)論框?yàn)槔覀儗⒂腥缦碌慕M件結(jié)構(gòu):

- CommentBox
  - CommentList
    - Comment
  - CommentForm

讓我們構(gòu)造 CommentBox 組件,它只是一個(gè)簡(jiǎn)單的 <div> 而已:

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

JSX語(yǔ)法

首先你注意到 JavaScript 代碼中 XML 式的語(yǔ)法語(yǔ)句。我們有一個(gè)簡(jiǎn)單的預(yù)編譯器,用于將這種語(yǔ)法糖轉(zhuǎn)換成純的 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 語(yǔ)法是可選的,但是我們發(fā)現(xiàn) JSX 語(yǔ)句比純 JavaScript 更加容易使用。閱讀更多關(guān)于 JSX 語(yǔ)法的文章。

發(fā)生了什么

我們通過(guò) JavaScript 對(duì)象傳遞一些方法到 React.createClass() 來(lái)創(chuàng)建一個(gè)新的React組件。其中最重要的方法是render,該方法返回一顆 React 組件樹,這棵樹最終將會(huì)渲染成 HTML。

這個(gè) <div> 標(biāo)簽不是真實(shí)的DOM節(jié)點(diǎn);他們是 React div 組件的實(shí)例。你可以認(rèn)為這些就是React知道如何處理的標(biāo)記或者一些數(shù)據(jù)。React 是安全的。我們不生成 HTML 字符串,因此默認(rèn)阻止了 XSS 攻擊。

你沒(méi)有必要返回基本的 HTML。你可以返回一個(gè)你(或者其他人)創(chuàng)建的組件樹。這就使得 React 變得組件化:一個(gè)關(guān)鍵的前端維護(hù)原則。

React.render() 實(shí)例化根組件,啟動(dòng)框架,注入標(biāo)記到原始的 DOM 元素中,作為第二個(gè)參數(shù)提供。

制作組件

讓我們?yōu)?nbsp;CommentList 和 CommentForm 構(gòu)建骨架,這也會(huì)是一些簡(jiǎn)單的 <div> :

// tutorial2.jsvar 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>
    );
  }
});

下一步,更新 CommentBox 組件,使用這些新的組件:

// tutorial3.jsvar CommentBox = React.createClass({
  render: function() {    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList />
        <CommentForm />
      </div>
    );
  }
});

注意我們是如何混合 HTML 標(biāo)簽和我們創(chuàng)建的組件。HTML 組件就是普通的 React 組件,就像你定義的一樣,只有一點(diǎn)不一樣。JSX 編譯器會(huì)自動(dòng)重寫 HTML 標(biāo)簽為 React.createElement(tagName) 表達(dá)式,其它什么都不做。這是為了避免全局命名空間污染。

組件屬性

讓我們創(chuàng)建我們的第三個(gè)組件,Comment。我們想傳遞給它作者名字和評(píng)論文本,以便于我們能夠?qū)γ恳粋€(gè)獨(dú)立的評(píng)論重用相同的代碼。首先讓我們添加一些評(píng)論到 CommentList

// tutorial4.jsvar 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>
    );
  }
});

請(qǐng)注意,我們已經(jīng)從父節(jié)點(diǎn) CommentList 組件傳遞給子節(jié)點(diǎn) Comment 組件一些數(shù)據(jù)。例如,我們傳遞了 Pete Hunt(通過(guò)一個(gè)屬性)和 This is one comment (通過(guò)類似于XML的子節(jié)點(diǎn))給第一個(gè) Comment。從父節(jié)點(diǎn)傳遞到子節(jié)點(diǎn)的數(shù)據(jù)稱為 props,是屬性(properties)的縮寫。

使用props

讓我們創(chuàng)建評(píng)論組件。通過(guò) props,就能夠從中讀取到從 CommentList 傳遞過(guò)來(lái)的數(shù)據(jù),然后渲染一些標(biāo)記:

// tutorial5.jsvar Comment = React.createClass({
  render: function() {    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {this.props.children}
      </div>
    );
  }
});

在 JSX 中通過(guò)將 JavaScript 表達(dá)式放在大括號(hào)中(作為屬性或者子節(jié)點(diǎn)),你可以生成文本或者 React 組件到節(jié)點(diǎn)樹中。我們?cè)L問(wèn)傳遞給組件的命名屬性作為 this.props 的鍵,任何內(nèi)嵌的元素作為 this.props.children。

添加 Markdown

Markdown 是一種簡(jiǎn)單的格式化內(nèi)聯(lián)文本的方式。例如,用星號(hào)包裹文本將會(huì)使其強(qiáng)調(diào)突出。

首先,添加第三方的 Showdown 庫(kù)到你的應(yīng)用。這是一個(gè)JavaScript庫(kù),處理 Markdown 文本并且轉(zhuǎn)換為原始的 HTML。這需要在你的頭部添加一個(gè) script 標(biāo)簽(我們已經(jīng)在 React 操練場(chǎng)上包含了這個(gè)標(biāo)簽):

 <!-- index.html -->
 <head>
  <title>Hello React</title>
  <script src="http://fb.me/react-{{site.react_version}}.js" rel="external nofollow" ></script>
  <script src="http://fb.me/JSXTransformer-{{site.react_version}}.js" rel="external nofollow" ></script>
  <script src="http://code.jquery.com/jquery-1.10.0.min.js" rel="external nofollow" ></script>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js" rel="external nofollow" ></script>
 </head>

下一步,讓我們轉(zhuǎn)換評(píng)論文本為 Markdown 格式,然后輸出它:

// tutorial6.jsvar converter = new Showdown.converter();var Comment = React.createClass({
  render: function() {    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {converter.makeHtml(this.props.children.toString())}
      </div>
    );
  }
});

我們?cè)谶@里唯一需要做的就是調(diào)用 Showdown 庫(kù)。我們需要把this.props.children從 React 的包裹文本轉(zhuǎn)換成 Showdown 能處理的原始的字符串,所以我們顯示地調(diào)用了toString()。

但是這里有一個(gè)問(wèn)題!我們渲染的評(píng)論在瀏覽器里面看起來(lái)像這樣:“<p>This is <em>another</em>comment</p>”。我們想這些標(biāo)簽真正地渲染成 HTML。

那是 React 在保護(hù)你免受 XSS 攻擊。這里有一種方法解決這個(gè)問(wèn)題,但是框架會(huì)警告你別使用這種方法:

// tutorial7.jsvar converter = new Showdown.converter();var Comment = React.createClass({
  render: function() {    var rawMarkup = converter.makeHtml(this.props.children.toString());    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={{"{{"}}__html: rawMarkup}} />
      </div>
    );
  }
});

這是一個(gè)特殊的 API,故意讓插入原始的 HTML 變得困難,但是對(duì)于 Showdown,我們將利用這個(gè)后門。

記住: 使用這個(gè)功能,你會(huì)依賴于 Showdown 的安全性。

接入數(shù)據(jù)模型

到目前為止,我們已經(jīng)在源代碼里面直接插入了評(píng)論數(shù)據(jù)。相反,讓我們渲染一小塊JSON數(shù)據(jù)到評(píng)論列表。最終,數(shù)據(jù)將會(huì)來(lái)自服務(wù)器,但是現(xiàn)在,寫在你的源代碼中:

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

我們需要用一種模塊化的方式將數(shù)據(jù)傳入到 CommentList。修改 CommentBox 和 React.render() 方法,通過(guò) props 傳遞數(shù)據(jù)到 CommentList

// tutorial9.js
var CommentBox = React.createClass({
  render: function() {
    return (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.props.data} />
        <CommentForm />
      </div>
    );
  }
});

React.render(  <CommentBox data={data} />,
  document.getElementById('content')
);

現(xiàn)在數(shù)據(jù)在 CommentList 中可用了,讓我們動(dòng)態(tài)地渲染評(píng)論:

// tutorial10.jsvar CommentList = React.createClass({
  render: function() {    var commentNodes = this.props.data.map(function (comment) {      return (        <Comment author={comment.author}>
          {comment.text}        </Comment>
      );
    });    return (      <div className="commentList">
        {commentNodes}      </div>
    );
  }
});

就是這樣!

從服務(wù)器獲取數(shù)據(jù)

讓我們用一些從服務(wù)器獲取的動(dòng)態(tài)數(shù)據(jù)替換硬編碼的數(shù)據(jù)。我們將移除數(shù)據(jù)屬性,用獲取數(shù)據(jù)的URL來(lái)替換它:

// tutorial11.jsReact.render(
  <CommentBox url="comments.json" />,
  document.getElementById('content')
);

這個(gè)組件和前面的組件是不一樣的,因?yàn)樗仨氈匦落秩咀约?。該組件將不會(huì)有任何數(shù)據(jù),直到請(qǐng)求從服務(wù)器返回,此時(shí)該組件或許需要渲染一些新的評(píng)論。

響應(yīng)狀態(tài)變化(Reactive state)

到目前為止,每一個(gè)組件都根據(jù)自己的 props 渲染了自己一次。props 是不可變的:它們從父節(jié)點(diǎn)傳遞過(guò)來(lái),被父節(jié)點(diǎn)“擁有”。為了實(shí)現(xiàn)交互,我們給組件引進(jìn)了可變的 state。this.state 是組件私有的,可以通過(guò)調(diào)用this.setState() 來(lái)改變它。當(dāng)狀態(tài)更新之后,組件重新渲染自己。

render() methods are written declaratively as functions of this.props and this.state. 框架確保UI始終和輸入保持一致。

當(dāng)服務(wù)器獲取數(shù)據(jù)的時(shí)候,我們將會(huì)用已有的數(shù)據(jù)改變?cè)u(píng)論。讓我們給 CommentBox 組件添加一個(gè)評(píng)論數(shù)組作為它的狀態(tài):

// tutorial12.jsvar CommentBox = React.createClass({
  getInitialState: function() {    return {data: []};
  },
  render: function() {    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

getInitialState()在組件的生命周期中僅執(zhí)行一次,設(shè)置組件的初始化狀態(tài)。

更新狀態(tài)

當(dāng)組件第一次創(chuàng)建的時(shí)候,我們想從服務(wù)器獲取(使用GET方法)一些JSON數(shù)據(jù),更新狀態(tài),反映出最新的數(shù)據(jù)。在真實(shí)的應(yīng)用中,這將會(huì)是一個(gè)動(dòng)態(tài)功能點(diǎn),但是對(duì)于這個(gè)例子,我們將會(huì)使用一個(gè)靜態(tài)的JSON文件來(lái)使事情變得簡(jiǎn)單:

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

我們將會(huì)使用jQuery幫助發(fā)出一個(gè)一步的請(qǐng)求到服務(wù)器。

注意:因?yàn)檫@會(huì)變成一個(gè)AJAX應(yīng)用,你將會(huì)需要使用一個(gè)web服務(wù)器來(lái)開發(fā)你的應(yīng)用,而不是一個(gè)放置在你的文件系統(tǒng)上面的一個(gè)文件。如上所述,我們已經(jīng)在GitHub上面提供了幾個(gè)你可以使用的服務(wù)器。這些服務(wù)器提供了你學(xué)習(xí)下面教程所需的功能。

// 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 (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

在這里,componentDidMount是一個(gè)在組件被渲染的時(shí)候React自動(dòng)調(diào)用的方法。動(dòng)態(tài)更新的關(guān)鍵點(diǎn)是調(diào)用this.setState()。我們把舊的評(píng)論數(shù)組替換成從服務(wù)器拿到的新的數(shù)組,然后UI自動(dòng)更新。正是有了這種響應(yīng)式,一個(gè)小的改變都會(huì)觸發(fā)實(shí)時(shí)的更新。這里我們將使用簡(jiǎn)單的輪詢,但是你可以簡(jiǎn)單地使用WebSockets或者其它技術(shù)。

// 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 (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

React.render(  <CommentBox url="comments.json" pollInterval={2000} />,
  document.getElementById('content')
);

我們?cè)谶@里所做的就是把AJAX調(diào)用移到一個(gè)分離的方法中去,組件第一次加載以及之后每隔兩秒鐘,調(diào)用這個(gè)方法。嘗試在你的瀏覽器中運(yùn)行,然后改變comments.json文件;在兩秒鐘之內(nèi),改變將會(huì)顯示出來(lái)!

添加新的評(píng)論

現(xiàn)在是時(shí)候構(gòu)造表單了。我們的CommentForm組件應(yīng)該詢問(wèn)用戶的名字和評(píng)論內(nèi)容,然后發(fā)送一個(gè)請(qǐng)求到服務(wù)器,保存這條評(píng)論。

// tutorial15.jsvar CommentForm = React.createClass({
  render: function() {    return (
      <form className="commentForm">
        <input type="text" placeholder="Your name" />
        <input type="text" placeholder="Say something..." />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

讓我們使表單可交互。當(dāng)用戶提交表單的時(shí)候,我們應(yīng)該清空表單,提交一個(gè)請(qǐng)求到服務(wù)器,然后刷新評(píng)論列表。首先,讓我們監(jiān)聽表單的提交事件和清空表單。

// 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 (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});
事件

React使用駝峰命名規(guī)范的方式給組件綁定事件處理器。我們給表單綁定一個(gè)onSubmit處理器,用于當(dāng)表單提交了合法的輸入后清空表單字段。

在事件回調(diào)中調(diào)用preventDefault()來(lái)避免瀏覽器默認(rèn)地提交表單。

Refs

我們利用Ref屬性給子組件命名,this.refs引用組件。我們可以在組件上調(diào)用getDOMNode()獲取瀏覽器本地的DOM元素。

回調(diào)函數(shù)作為屬性

當(dāng)用戶提交評(píng)論的時(shí)候,我們需要刷新評(píng)論列表來(lái)加進(jìn)這條新評(píng)論。在CommentBox中完成所有邏輯是合適的,因?yàn)?code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">CommentBox擁有代表評(píng)論列表的狀態(tài)(state)。

我們需要從子組件傳回?cái)?shù)據(jù)到它的父組件。我們?cè)诟附M件的render方法中做這件事:傳遞一個(gè)新的回調(diào)函數(shù)(handleCommentSubmit)到子組件,綁定它到子組件的onCommentSubmit事件上。無(wú)論事件什么時(shí)候觸發(fā),回調(diào)函數(shù)都將會(huì)被調(diào)用:

// 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 (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});

當(dāng)用戶提交表單的時(shí)候,讓我們?cè)?code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; padding: 2px 4px; color: rgb(45, 133, 202); background-color: rgb(249, 242, 244);">CommentForm中調(diào)用這個(gè)回調(diào)函數(shù):

// 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 (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

現(xiàn)在回調(diào)函數(shù)已經(jīng)就緒,唯一我們需要做的就是提交到服務(wù)器,然后刷新列表:

// 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 (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});

優(yōu)化:提前更新

我們的應(yīng)用現(xiàn)在已經(jīng)完成了所有功能,但是在你的評(píng)論出現(xiàn)在列表之前,你必須等待請(qǐng)求完成,感覺(jué)很慢。我們可以提前添加這條評(píng)論到列表中,從而使應(yīng)用感覺(jué)更快。

// 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 (      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
});

祝賀你!

你剛剛通過(guò)一些簡(jiǎn)單步驟夠早了一個(gè)評(píng)論框。了解更多關(guān)于為什么使用React的內(nèi)容,或者深入學(xué)習(xí)API參考,開始專研!祝你好運(yùn)!


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)