教程-Tutorial

我們將建造一個(gè)簡(jiǎn)單但是實(shí)用的評(píng)論框八毯,你可以把它用在博客或者作為一個(gè)基礎(chǔ)版的實(shí)時(shí)評(píng)論組件昌阿,比如淘寶山害、微博村生。

我們將提供:

  • 所有評(píng)論的查看
  • 一個(gè)提供評(píng)論功能的表單
  • 將你定制的后端與之關(guān)聯(lián)

它還有一些優(yōu)雅的特性

  • 積極的評(píng)論:提交之后的評(píng)論會(huì)馬上出現(xiàn)在評(píng)論列表嘉涌,因此它看起來(lái)很快妻熊。
  • 動(dòng)態(tài)更新:其它用戶的評(píng)論將會(huì)實(shí)時(shí)出現(xiàn)。
  • Markdown 支持:用戶可用MarkDown語(yǔ)法給自己的評(píng)論排版仑最。

想跳過(guò)所有步驟僅僅查看代碼固耘?

都在 GitHub 上

啟動(dòng)一個(gè)服務(wù)器

為了開(kāi)始我們的教程,我們需要一個(gè)運(yùn)行中的服務(wù)器词身。它僅僅提供一個(gè)用來(lái)獲取和提交數(shù)據(jù)的 API 端點(diǎn)服務(wù)厅目。為了做起來(lái)更加簡(jiǎn)單,我們用簡(jiǎn)單的腳本語(yǔ)言來(lái)搭建服務(wù)法严。你可以查看源碼或者下載壓縮文件來(lái)包含一切我們需要的環(huán)境并開(kāi)始我們的教程损敷。

開(kāi)始搭建

我們致力于讓本教程變得相對(duì)簡(jiǎn)單,在我們上文提到的服務(wù)器的包中深啤,包含著一個(gè) HTML 文件拗馒,我們將用它來(lái)開(kāi)始工作。在你喜歡的編輯器中打開(kāi) public/index.html溯街,它看起來(lái)應(yīng)該像下面這樣:

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>React Tutorial</title>
    <script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script>
    <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
    <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
    <script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
    <script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/babel" src="scripts/example.js"></script>
    <script type="text/babel">
      // To get started with this tutorial running your own code, simply remove
      // the script tag loading scripts/example.js and start writing code here.
    </script>
  </body>
</html>

在接下來(lái)的教程中诱桂,我們將在 script 標(biāo)簽中編寫(xiě)JavaScript代碼,我們沒(méi)有任何先進(jìn)的動(dòng)態(tài)加載功能因此你只需在保存后刷新你的瀏覽器就可以看到你的更新呈昔。通過(guò)在瀏覽器中打開(kāi)http://localhost:3000來(lái)跟進(jìn)你的進(jìn)度(在啟動(dòng)服務(wù)器之后)挥等。當(dāng)你第一次加載這個(gè)文件并且沒(méi)有做任何改動(dòng)時(shí),你將會(huì)看到我們要打造功能的最終樣子堤尾。當(dāng)你準(zhǔn)備好接下來(lái)的教程了肝劲,只需要?jiǎng)h除<script>標(biāo)簽。

備注:
我們包含進(jìn)了JQuery庫(kù)因?yàn)槲覀兿胍?jiǎn)化將來(lái)用到的AJAX代碼郭宝,但是它并不是強(qiáng)制地為React工作辞槐。

你的第一個(gè)組件

React 是模塊化的,由組件構(gòu)成的粘室。拿我們的評(píng)論框舉例榄檬,我們將會(huì)有如下的幾個(gè)組件:

- CommentBox
  - CommentList
    - Comment
  - CommentForm

讓我們建造一個(gè)CommentBox組件,它僅僅是一個(gè)簡(jiǎn)單的<div>

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

注意到原生的 HTML 元素采用小駝峰命名法衔统,同時(shí)定制的 React 類(lèi)名采用大駝峰命名法鹿榜。

JSX 語(yǔ)法

你第一個(gè)注意到的會(huì)是 XML 語(yǔ)法聯(lián)合在你的JavaScript 中先朦。我們有一個(gè)前置編譯器來(lái)將這種語(yǔ)法糖轉(zhuǎn)化為樸素的JS語(yǔ)法:

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

語(yǔ)法的選擇是可選的但我們發(fā)現(xiàn)JSX語(yǔ)法比樸素的JS語(yǔ)法更加好用。在JSX 語(yǔ)法文章中閱讀更多犬缨。

接下來(lái)做什么

我們通過(guò)在JS類(lèi)中的一些方法如 React.createClass()來(lái)創(chuàng)建一個(gè) React 組件喳魏。最重要的方法是調(diào)用 render(),該方法返回一個(gè)組件樹(shù)怀薛,該樹(shù)用來(lái)渲染成HTML刺彩。
<div>標(biāo)簽并不是真實(shí)的 DOM 節(jié)點(diǎn),他們是實(shí)例化的 React div組件枝恋。你可以把它們想象成React用來(lái)處理數(shù)據(jù)的標(biāo)記创倔。React 是安全的,我們不生成 HTML 字符串焚碌,所以默認(rèn)有 XSS 跨站腳本攻擊的防護(hù)畦攘。
你不用返回一個(gè)基本的 HTML。你可以返回一個(gè)自己或他人的組件樹(shù)十电。這就是React的組成:前端可維護(hù)的信條知押。
ReactDOM.render() 實(shí)例化根組件,啟動(dòng)框架鹃骂,把標(biāo)記映射成新的DOM 元素台盯。
重要的是ReactDOM.render放在腳本的最底部,ReactDOM.render應(yīng)該確保等所有組件被初始化完畢再調(diào)用畏线。

拼裝組件

讓我們創(chuàng)建CommentListCommentForm的骨骼静盅,同樣采用簡(jiǎn)單的<div>,添加這兩個(gè)組件到你的文件中寝殴,保持CommentBox的定義和ReactDOM.render的調(diào)用:

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

接下來(lái)蒿叠,更新CommentBox來(lái)使用新的組件:

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

注意我們是怎么把HTML 標(biāo)簽和我們自定義的組件混用的。HTML 組件是正規(guī)的 React 組件蚣常,就像你自己定義的一樣市咽,有一點(diǎn)不同的是。JSX編譯器會(huì)自動(dòng)地把HTML標(biāo)簽替換成React.createElement(tagName)表達(dá)式并且把它們單獨(dú)放置史隆。這樣可以避免全局命名空間內(nèi)的垃圾數(shù)據(jù)魂务。

使用屬性

讓我們創(chuàng)建 Comment組件,它依靠父組件傳遞給他的數(shù)據(jù)泌射。從父組件傳遞過(guò)來(lái)的數(shù)據(jù)通過(guò)屬性的方式傳遞給子組件。這些屬性通過(guò)this.props訪問(wèn)鬓照。通過(guò)屬性熔酷,我們可以讀取通過(guò)CommentList傳遞給Comment的數(shù)據(jù),并實(shí)施一些標(biāo)記:

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

花括號(hào)中的JS表達(dá)式被嵌套在JSX中豺裆,你可以把文本或者React組件放入樹(shù)中拒秘,我們通過(guò)命名的屬性訪問(wèn)傳遞過(guò)來(lái)的數(shù)據(jù)号显,并且訪問(wèn)元素中的數(shù)據(jù)。

組件的屬性

既然我們定義了Comment屬性躺酒,我們希望傳遞一些屬性給它押蚤。這可以允許我們對(duì)代碼進(jìn)行復(fù)用。現(xiàn)在羹应,讓我們給CommentList中加一些評(píng)論揽碘。

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

注意,我們通過(guò)CommentList組件傳遞一些數(shù)據(jù)給了Comment組件园匹。比如雳刺,我們傳遞了 Pete HuntThis is one commentComment。如上文那樣裸违,Comment組件通過(guò)this.props.authorthis.props.children來(lái)訪問(wèn)這些屬性掖桦。

添加Markdown 支持

Markdown是格式化你的文本的一種簡(jiǎn)單的方法。比如供汛,用幸好環(huán)繞文本會(huì)讓它加重枪汪。
在本教程中,我們使用第三發(fā)的庫(kù)remarkable來(lái)實(shí)現(xiàn)怔昨。在初始的頁(yè)面中料饥,我們已經(jīng)包含了這個(gè)庫(kù),所以我們可以直接使用它朱监。

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

我們?cè)谶@里做的事情就是調(diào)用 remarkable 庫(kù)岸啡,我們需要把 this.props.children 的React的文字換行格式轉(zhuǎn)化成未加工的字符串以使 remarkable 很好的工作。
問(wèn)題出現(xiàn)了赫编,我們的加工過(guò)的字符串成了這樣子<p>This is <em>another</em> comment</p>巡蘸,我們希望這些標(biāo)簽編程HTML。
這是因?yàn)镽eact為了防止XSS 攻擊所做的工作擂送。有一種方法擺脫這種防護(hù)悦荒,但是框架會(huì)警告你最好不要這么做。

// tutorial7.js
var Comment = React.createClass({
  rawMarkup: function() {
    var md = new Remarkable();
    var rawMarkup = md.render(this.props.children.toString());
    return { __html: rawMarkup };
  },

  render: function() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={this.rawMarkup()} />
      </div>
    );
  }
});

這是一個(gè)特殊的API 故意使插入一個(gè)未加工的HTML變得困難嘹吨,但是為了使用 remarkable 我們可以利用這個(gè)后門(mén)搬味。

聯(lián)系數(shù)據(jù)模型

目前為止,我們直接在源代碼中插入了評(píng)論◇翱剑現(xiàn)在碰纬,讓我們用json格式的數(shù)據(jù)來(lái)填充評(píng)論列表。事實(shí)上這些數(shù)據(jù)將來(lái)自服務(wù)器问芬,但是現(xiàn)在我們先把它寫(xiě)入源碼中悦析。

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

我們需要以一種模塊化的方式將這個(gè)數(shù)據(jù)傳入到 CommentList。修改 CommentBox 和 ReactDOM.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>
    );
  }
});

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

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

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

就是這樣亭螟!

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

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

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

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

注意: 此代碼在這個(gè)階段不會(huì)工作衰琐。

Reactive state

迄今為止,基于它自己的props也糊,每個(gè)組件都渲染了自己一次。props 是不可變的:它們從父級(jí)傳來(lái)并被父級(jí)“擁有”羡宙。為了實(shí)現(xiàn)交互狸剃,我們給組件引進(jìn)了可變的 state。this.state 是組件私有的狗热,可以通過(guò)調(diào)用 this.setState() 改變它钞馁。每當(dāng)state更新,組件就重新渲染自己匿刮。

render() 方法被聲明為一個(gè)帶有 this.props 和 this.state 的函數(shù)僧凰。框架保證了 UI 總是與輸入一致熟丸。

當(dāng)服務(wù)器獲取數(shù)據(jù)時(shí)训措,我們將會(huì)改變我們已有的評(píng)論數(shù)據(jù)。讓我們給 CommentBox 組件添加一組評(píng)論數(shù)據(jù)作為它的狀態(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í)行一次光羞,并設(shè)置組件的初始狀態(tài)绩鸣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纱兑,隨后出現(xiàn)的幾起案子呀闻,更是在濱河造成了極大的恐慌,老刑警劉巖潜慎,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捡多,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡铐炫,警方通過(guò)查閱死者的電腦和手機(jī)垒手,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)驳遵,“玉大人淫奔,你說(shuō)我怎么就攤上這事〉探幔” “怎么了唆迁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)竞穷。 經(jīng)常有香客問(wèn)我唐责,道長(zhǎng),這世上最難降的妖魔是什么瘾带? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任鼠哥,我火速辦了婚禮,結(jié)果婚禮上看政,老公的妹妹穿的比我還像新娘朴恳。我一直安慰自己,他們只是感情好允蚣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布于颖。 她就那樣靜靜地躺著,像睡著了一般嚷兔。 火紅的嫁衣襯著肌膚如雪森渐。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天冒晰,我揣著相機(jī)與錄音同衣,去河邊找鬼。 笑死壶运,一個(gè)胖子當(dāng)著我的面吹牛耐齐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒋情,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼埠况,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了恕出?” 一聲冷哼從身側(cè)響起询枚,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浙巫,沒(méi)想到半個(gè)月后金蜀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡的畴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年渊抄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丧裁。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡护桦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煎娇,到底是詐尸還是另有隱情二庵,我是刑警寧澤贪染,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站催享,受9級(jí)特大地震影響杭隙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜因妙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一痰憎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧攀涵,春花似錦铣耘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至据德,卻和暖如春鳄乏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棘利。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工橱野, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人善玫。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓水援,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親茅郎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蜗元,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 按照慣例,先給ReactJS背書(shū) React是一個(gè)Facebook開(kāi)發(fā)的UI庫(kù)系冗,于2013年5月開(kāi)源奕扣,并迅速的從最...
    艾倫先生閱讀 3,222評(píng)論 1 12
  • 關(guān)于JSX 考慮這樣一段代碼:const element = Hello, world! ;這段代碼既不是字符串...
    帶三本書(shū)閱讀 366評(píng)論 0 1
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,048評(píng)論 2 35
  • 突然記起來(lái)高三時(shí)候幾乎每天晚上都要去吃校門(mén)口對(duì)面的麻辣燙,永遠(yuǎn)不會(huì)忘記第一次點(diǎn)的時(shí)候點(diǎn)了18塊掌敬,這別的女生最多...
    寫(xiě)文的詩(shī)琪閱讀 207評(píng)論 0 0
  • 學(xué)校老師有要求惯豆,假期里要看86版《西游記》。讓兒子在網(wǎng)絡(luò)電視中幾個(gè)客戶端中尋找奔害,找不到這部楷兽,只能在臺(tái)腦中看...
    李梓榮媽媽閱讀 272評(píng)論 0 0