在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 教程
顯示數(shù)據(jù)
組件的引用
Controlled Input 值為 null 的情況
Reconciliation
子 props 的類型
組件的詳細說明和生命周期
傳遞 Props
特殊的非 DOM 屬性
組件 API
PureRenderMixin
雙向綁定輔助工具
瀏覽器中的工作原理
深入 JSX
表單組件
Dangerously Set innerHTML
入門
JSX 中的 If-Else
克隆組件
教程
更多的關于Refs
JSX 的 false 處理
高級性能
Mounting 后 componentWillReceiveProps 未被觸發(fā)
簡介
測試工具集
JSX 陷阱
工具集成(ToolingIntegration)
公開組件功能
通過 AJAX 加載初始數(shù)據(jù)
事件系統(tǒng)
可復用組件
this.props.children undefined
不可變數(shù)據(jù)的輔助工具(Immutability Helpers)
動態(tài)交互式用戶界面
組件的 DOM 事件監(jiān)聽
復合組件
動畫
插件
JSX 展開屬性
行內(nèi)樣式
性能分析工具
類名操作
與其他類庫并行使用 React
鍵控的片段
標簽和屬性支持
組件間的通信
React (虛擬)DOM 術語
JSX 根節(jié)點的最大數(shù)量
在樣式props中快速制定像素值
頂層 API
深入理解 React
自閉合標簽
為什么使用 React?
getInitialState 里的 Props 是一個反模式
與 DOM 的差異

教程

我們將構建一個簡單卻真實的評論框,你可以將它放入你的博客,類似disqus、livefyre、facebook提供的實時評論的基礎版。

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

  • 一個展示所有評論的視圖
  • 一個提交評論的表單
  • 用于構建自定制后臺的接口鏈接(hooks)

同時也包含一些簡潔的特性:

  • 評論體驗優(yōu)化: 評論在保存到服務器之前就展現(xiàn)在評論列表,因此用戶體驗很快。
  • 實時更新: 其他用戶的評論將會實時展示。
  • Markdown格式: 用戶可以使用MarkDown格式來編輯文本。

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

所有代碼都在GitHub。

運行一個服務器

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

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

開始學習

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

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

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

注意:

因為我們想簡化 ajax 請求代碼,所以在這里引入 jQuery,但是它對 React 并不是必須的。

你的第一個組件

React 中全是模塊化、可組裝的組件。以我們的評論框為例,我們將有如下的組件結構:

- CommentBox
  - CommentList
    - Comment
  - CommentForm

讓我們構造 CommentBox 組件,它只是一個簡單的 <div> 而已:

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

JSX語法

首先你注意到 JavaScript 代碼中 XML 式的語法語句。我們有一個簡單的預編譯器,用于將這種語法糖轉換成純的 JavaScript 代碼:

// tutorial1-raw.js
var 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 語法是可選的,但是我們發(fā)現(xiàn) JSX 語句比純 JavaScript 更加容易使用。閱讀更多關于 JSX 語法的文章。

發(fā)生了什么

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

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

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

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

制作組件

讓我們?yōu)?CommentListCommentForm 構建骨架,這也會是一些簡單的 <div>

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

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

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

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

組件屬性

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

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

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

使用props

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

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

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

添加 Markdown

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

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

 <!-- index.html -->
 <head>
  <title>Hello React</title>
  <script src="http://fb.me/react-{{site.react_version}}.js"></script>
  <script src="http://fb.me/JSXTransformer-{{site.react_version}}.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>
 </head>

下一步,讓我們轉換評論文本為 Markdown 格式,然后輸出它:

// tutorial6.js
var 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>
    );
  }
});

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

但是這里有一個問題!我們渲染的評論在瀏覽器里面看起來像這樣:“<p>This is <em>another</em> comment</p>”。我們想這些標簽真正地渲染成 HTML。

那是 React 在保護你免受 XSS 攻擊。這里有一種方法解決這個問題,但是框架會警告你別使用這種方法:

// tutorial7.js
var 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>
    );
  }
});

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

記?。?/strong> 使用這個功能,你會依賴于 Showdown 的安全性。

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

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

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

我們需要用一種模塊化的方式將數(shù)據(jù)傳入到 CommentList。修改 CommentBoxReact.render() 方法,通過 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 中可用了,讓我們動態(tài)地渲染評論:

// tutorial10.js
var 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>
    );
  }
});

就是這樣!

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

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

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

這個組件和前面的組件是不一樣的,因為它必須重新渲染自己。該組件將不會有任何數(shù)據(jù),直到請求從服務器返回,此時該組件或許需要渲染一些新的評論。

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

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

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

當服務器獲取數(shù)據(jù)的時候,我們將會用已有的數(shù)據(jù)改變評論。讓我們給 CommentBox 組件添加一個評論數(shù)組作為它的狀態(tài):

// tutorial12.js
var 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í)行一次,設置組件的初始化狀態(tài)。

更新狀態(tài)

當組件第一次創(chuàng)建的時候,我們想從服務器獲?。ㄊ褂肎ET方法)一些JSON數(shù)據(jù),更新狀態(tài),反映出最新的數(shù)據(jù)。在真實的應用中,這將會是一個動態(tài)功能點,但是對于這個例子,我們將會使用一個靜態(tài)的JSON文件來使事情變得簡單:

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

我們將會使用jQuery幫助發(fā)出一個一步的請求到服務器。

注意:因為這會變成一個AJAX應用,你將會需要使用一個web服務器來開發(fā)你的應用,而不是一個放置在你的文件系統(tǒng)上面的一個文件。如上所述,我們已經(jīng)在GitHub上面提供了幾個你可以使用的服務器。這些服務器提供了你學習下面教程所需的功能。

// tutorial13.js
var 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是一個在組件被渲染的時候React自動調(diào)用的方法。動態(tài)更新的關鍵點是調(diào)用this.setState()。我們把舊的評論數(shù)組替換成從服務器拿到的新的數(shù)組,然后UI自動更新。正是有了這種響應式,一個小的改變都會觸發(fā)實時的更新。這里我們將使用簡單的輪詢,但是你可以簡單地使用WebSockets或者其它技術。

// tutorial14.js
var 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')
);

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

添加新的評論

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

// tutorial15.js
var 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>
    );
  }
});

讓我們使表單可交互。當用戶提交表單的時候,我們應該清空表單,提交一個請求到服務器,然后刷新評論列表。首先,讓我們監(jiān)聽表單的提交事件和清空表單。

// tutorial16.js
var 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ī)范的方式給組件綁定事件處理器。我們給表單綁定一個onSubmit處理器,用于當表單提交了合法的輸入后清空表單字段。

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

Refs

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

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

當用戶提交評論的時候,我們需要刷新評論列表來加進這條新評論。在CommentBox中完成所有邏輯是合適的,因為CommentBox擁有代表評論列表的狀態(tài)(state)。

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

// tutorial17.js
var 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>
    );
  }
});

當用戶提交表單的時候,讓我們在CommentForm中調(diào)用這個回調(diào)函數(shù):

// tutorial18.js
var 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)就緒,唯一我們需要做的就是提交到服務器,然后刷新列表:

// tutorial19.js
var 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)化:提前更新

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

// tutorial20.js
var 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>
    );
  }
});

祝賀你!

你剛剛通過一些簡單步驟夠早了一個評論框。了解更多關于為什么使用React的內(nèi)容,或者深入學習API參考,開始專研!祝你好運!

下一篇:鍵控的片段