<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                我們將構建一個簡單卻真實的評論框,你可以將它放入你的博客,類似disqus、livefyre、facebook提供的實時評論的基礎版。 我們將提供以下內容: * 一個展示所有評論的視圖 * 一個提交評論的表單 * 用于構建自定制后臺的接口鏈接(hooks) 同時也包含一些簡潔的特性: * **評論體驗優化:**?評論在保存到服務器之前就展現在評論列表,因此用戶體驗很快。 * **實時更新:**?其他用戶的評論將會實時展示。 * **Markdown格式:**?用戶可以使用MarkDown格式來編輯文本。 目錄 : [TOC] ### 想要跳過所有的內容,只查看源代碼? [所有代碼都在GitHub。](https://github.com/reactjs/react-tutorial) ### 運行一個服務器 雖然它不是入門教程的必需品,但接下來我們會添加一個功能,發送?`POST`?ing請求到服務器。如果這是你熟知的事并且你想創建你自己的服務器,那么就這樣干吧。而對于另外的一部分人,為了讓你集中精力學習,而不用擔憂服務器端方面,我們已經用了以下一系列的語言編寫了簡單的服務器代碼 - JavaScript(使用Node.js),Python和Ruby。所有代碼都在GitHub。你可以[查看代碼](ttps://github.com/reactjs/react-tutorial/)或者[下載 zip 文件](https://github.com/reactjs/react-tutorial/archive/master.zip)來開始學習。 開始使用下載的教程,只需開始編輯?`public/index.html`?。 ### 開始學習 在這個教程里面,我們將使用放在 CDN 上預構建好的 JavaScript 文件。打開你最喜歡的編輯器,創建一個新的 HTML 文檔: ~~~ <!-- index.html --> <html> <head> <title>Hello React</title> <script src="http://fb.me/react-0.13.0.js"></script> <script src="http://fb.me/JSXTransformer-0.13.0.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`?組件,它只是一個簡單的?``?而已: ~~~ // 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 語法是可選的,但是我們發現 JSX 語句比純 JavaScript 更加容易使用。閱讀更多關于[JSX 語法的文章](http://reactjs.cn/react/docs/jsx-in-depth.html)。 #### 發生了什么 我們通過 JavaScript 對象傳遞一些方法到?`React.createClass()`?來創建一個新的React組件。其中最重要的方法是?`render`,該方法返回一顆 React 組件樹,這棵樹最終將會渲染成 HTML。 這個?``?標簽不是真實的DOM節點;他們是 React?`div`?組件的實例。你可以認為這些就是React知道如何處理的標記或者一些數據。React 是**安全的**。我們不生成 HTML 字符串,因此默認阻止了 XSS 攻擊。 你沒有必要返回基本的 HTML。你可以返回一個你(或者其他人)創建的組件樹。這就使得 React 變得**組件化**:一個關鍵的前端維護原則。 `React.render()`?實例化根組件,啟動框架,注入標記到原始的 DOM 元素中,作為第二個參數提供。 ## 制作組件 讓我們為?`CommentList`?和?`CommentForm`?構建骨架,這也會是一些簡單的?``?: ~~~ // 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 標簽和我們創建的組件。HTML 組件就是普通的 React 組件,就像你定義的一樣,只有一點不一樣。JSX 編譯器會自動重寫 HTML 標簽為`React.createElement(tagName)`?表達式,其它什么都不做。這是為了避免全局命名空間污染。 ### 組件屬性 讓我們創建我們的第三個組件,`Comment`。我們想傳遞給它作者名字和評論文本,以便于我們能夠對每一個獨立的評論重用相同的代碼。首先讓我們添加一些評論到?`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> ); } }); ~~~ 請注意,我們已經從父節點?`CommentList`?組件傳遞給子節點?`Comment`?組件一些數據。例如,我們傳遞了?_Pete Hunt_?(通過一個屬性)和?_This is one comment * (通過類似于XML的子節點)給第一個?`Comment`。從父節點傳遞到子節點的數據稱為 *_props**,是屬性(properties)的縮寫。 ### 使用props 讓我們創建評論組件。通過?**props**,就能夠從中讀取到從?`CommentList`?傳遞過來的數據,然后渲染一些標記: ~~~ // 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 表達式放在大括號中(作為屬性或者子節點),你可以生成文本或者 React 組件到節點樹中。我們訪問傳遞給組件的命名屬性作為?`this.props`?的鍵,任何內嵌的元素作為?`this.props.children`。 ### 添加 Markdown Markdown 是一種簡單的格式化內聯文本的方式。例如,用星號包裹文本將會使其強調突出。 首先,添加第三方的?**Showdown**?庫到你的應用。這是一個JavaScript庫,處理 Markdown 文本并且轉換為原始的 HTML。這需要在你的頭部添加一個 script 標簽(我們已經在 React 操練場上包含了這個標簽): ~~~ <!-- index.html --> <head> <title>Hello React</title> <script src="http://fb.me/react-0.13.0.js"></script> <script src="http://fb.me/JSXTransformer-0.13.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> </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> ); } }); ~~~ 我們在這里唯一需要做的就是調用 Showdown 庫。我們需要把`this.props.children`從 React 的包裹文本轉換成 Showdown 能處理的原始的字符串,所以我們顯示地調用了`toString()`。 但是這里有一個問題!我們渲染的評論在瀏覽器里面看起來像這樣:“``This is``another``?comment``”。我們想這些標簽真正地渲染成 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,我們將利用這個后門。 **記住:**?使用這個功能,你會依賴于 Showdown 的安全性。 ### 接入數據模型 到目前為止,我們已經在源代碼里面直接插入了評論數據。相反,讓我們渲染一小塊JSON數據到評論列表。最終,數據將會來自服務器,但是現在,寫在你的源代碼中: ~~~ // tutorial8.js var data = [ {author: "Pete Hunt", text: "This is one comment"}, {author: "Jordan Walke", text: "This is *another* comment"} ]; ~~~ 我們需要用一種模塊化的方式將數據傳入到?`CommentList`。修改?`CommentBox`?和`React.render()`?方法,通過 props 傳遞數據到?`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') ); ~~~ 現在數據在?`CommentList`?中可用了,讓我們動態地渲染評論: ~~~ // 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> ); } }); ~~~ 就是這樣! ### 從服務器獲取數據 讓我們用一些從服務器獲取的動態數據替換硬編碼的數據。我們將移除數據屬性,用獲取數據的URL來替換它: ~~~ // tutorial11.js React.render( <CommentBox url="comments.json" />, document.getElementById('content') ); ~~~ 這個組件和前面的組件是不一樣的,因為它必須重新渲染自己。該組件將不會有任何數據,直到請求從服務器返回,此時該組件或許需要渲染一些新的評論。 ### 響應狀態變化(Reactive state) 到目前為止,每一個組件都根據自己的 props 渲染了自己一次。`props`?是不可變的:它們從父節點傳遞過來,被父節點“擁有”。為了實現交互,我們給組件引進了可變的**state**。`this.state`?是組件私有的,可以通過調用?`this.setState()`?來改變它。當狀態更新之后,組件重新渲染自己。 `render()`?methods are written declaratively as functions of?`this.props`?and?`this.state`. 框架確保UI始終和輸入保持一致。 當服務器獲取數據的時候,我們將會用已有的數據改變評論。讓我們給?`CommentBox`?組件添加一個評論數組作為它的狀態: ~~~ // 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()`在組件的生命周期中僅執行一次,設置組件的初始化狀態。 #### 更新狀態 當組件第一次創建的時候,我們想從服務器獲取(使用GET方法)一些JSON數據,更新狀態,反映出最新的數據。在真實的應用中,這將會是一個動態功能點,但是對于這個例子,我們將會使用一個靜態的JSON文件來使事情變得簡單: ~~~ // tutorial13.json [ {"author": "Pete Hunt", "text": "This is one comment"}, {"author": "Jordan Walke", "text": "This is *another* comment"} ] ~~~ 我們將會使用jQuery幫助發出一個一步的請求到服務器。 注意:因為這會變成一個AJAX應用,你將會需要使用一個web服務器來開發你的應用,而不是一個放置在你的文件系統上面的一個文件。[如上所述](http://reactjs.cn/react/docs/tutorial.html#running-a-server),我們已經在[GitHub](https://github.com/reactjs/react-tutorial/)上面提供了幾個你可以使用的服務器。這些服務器提供了你學習下面教程所需的功能。 ~~~ // 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自動調用的方法。動態更新的關鍵點是調用`this.setState()`。我們把舊的評論數組替換成從服務器拿到的新的數組,然后UI自動更新。正是有了這種響應式,一個小的改變都會觸發實時的更新。這里我們將使用簡單的輪詢,但是你可以簡單地使用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調用移到一個分離的方法中去,組件第一次加載以及之后每隔兩秒鐘,調用這個方法。嘗試在你的瀏覽器中運行,然后改變`comments.json`文件;在兩秒鐘之內,改變將會顯示出來! ### 添加新的評論 現在是時候構造表單了。我們的`CommentForm`組件應該詢問用戶的名字和評論內容,然后發送一個請求到服務器,保存這條評論。 ~~~ // 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> ); } }); ~~~ 讓我們使表單可交互。當用戶提交表單的時候,我們應該清空表單,提交一個請求到服務器,然后刷新評論列表。首先,讓我們監聽表單的提交事件和清空表單。 ~~~ // 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使用駝峰命名規范的方式給組件綁定事件處理器。我們給表單綁定一個`onSubmit`處理器,用于當表單提交了合法的輸入后清空表單字段。 在事件回調中調用`preventDefault()`來避免瀏覽器默認地提交表單。 ##### Refs 我們利用`Ref`屬性給子組件命名,`this.refs`引用組件。我們可以在組件上調用`getDOMNode()`獲取瀏覽器本地的DOM元素。 ##### 回調函數作為屬性 當用戶提交評論的時候,我們需要刷新評論列表來加進這條新評論。在`CommentBox`中完成所有邏輯是合適的,因為`CommentBox`擁有代表評論列表的狀態(state)。 我們需要從子組件傳回數據到它的父組件。我們在父組件的`render`方法中做這件事:傳遞一個新的回調函數(`handleCommentSubmit`)到子組件,綁定它到子組件的`onCommentSubmit`事件上。無論事件什么時候觸發,回調函數都將會被調用: ~~~ // 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`中調用這個回調函數: ~~~ // 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> ); } }); ~~~ 現在回調函數已經就緒,唯一我們需要做的就是提交到服務器,然后刷新列表: ~~~ // 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> ); } }); ~~~ ### 優化:提前更新 我們的應用現在已經完成了所有功能,但是在你的評論出現在列表之前,你必須等待請求完成,感覺很慢。我們可以提前添加這條評論到列表中,從而使應用感覺更快。 ~~~ // 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](http://reactjs.cn/react/docs/why-react.html)的內容,或者深入學習[API參考](http://reactjs.cn/react/docs/top-level-api.html),開始專研!祝你好運!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看