摘要:例子全解析近些時(shí)間一直在關(guān)注,關(guān)于如何學(xué)習(xí)可以參照鏈接的文章自行制定計(jì)劃。千里之行,始于足下。此外,輸出的內(nèi)容要解析為,而在默認(rèn)情況下,基于預(yù)防攻擊的考慮,對(duì)輸出的內(nèi)容是不解析為的。
React-tutorial例子全解析
Talk is cheap,Show me the code
近些時(shí)間一直在關(guān)注React,關(guān)于如何學(xué)習(xí)React可以參照鏈接的文章自行制定計(jì)劃。千里之行,始于足下。本文是React官方的教程上的一個(gè)例子,通過(guò)詳細(xì)地學(xué)習(xí),從中收獲不少,特此做了筆記,與大家共享交流進(jìn)步。
起步下載例子,然后進(jìn)行解壓
由于采用的node環(huán)境,因此下載解壓之后,只需在所在目錄運(yùn)行
npm install node server.js
采用默認(rèn)端口設(shè)置,只需打開瀏覽器,訪問(wèn)http://localhost:3000/
目錄結(jié)構(gòu)說(shuō)明react-tutorial
--node_modules --body-parser:express中間件,用于接收和解析json數(shù)據(jù) --express:express框架 --public --css --base.css:基本樣式文件 --scripts -- example.js:React應(yīng)用js文件 index.html:基本的HTML結(jié)構(gòu) --.editorconfig:用于在不同的編輯器中統(tǒng)一編輯風(fēng)格(文件編碼)的配置文件 --.gitignore:git相關(guān)配置文件 --app.json:web app的相關(guān)信息 --comments.json:上傳的評(píng)論數(shù)據(jù) --LICENSE:項(xiàng)目代碼使用協(xié)議 --package.json:項(xiàng)目所依賴的包,npm install的安裝包的配置文件 --README.md:項(xiàng)目說(shuō)明書,里面有使用說(shuō)明 --requirements.txt:不清楚 --server.js:服務(wù)器端的js代碼App功能
此項(xiàng)目構(gòu)建了一個(gè)簡(jiǎn)單的應(yīng)用,如圖所示
服務(wù)器端服務(wù)器端的功能還是相對(duì)簡(jiǎn)單的,通過(guò)代碼注釋的形式來(lái)分析
導(dǎo)入了依賴的模塊
var fs = require("fs"); //讀寫文件 var path = require("path"); //路徑 var express = require("express"); //express框架 var bodyParser = require("body-parser"); //中間件
生成app,并且進(jìn)行配置
//獲取comments.json文件的路徑 var COMMENTS_FILE = path.join(__dirname, "comments.json"); //設(shè)置端口 app.set("port", (process.env.PORT || 3000)); //設(shè)置靜態(tài)文件的文件目錄路徑 app.use("/", express.static(path.join(__dirname, "public"))); //啟用bodyParser中間件接收請(qǐng)求,并且接收并解析json數(shù)據(jù) app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true}));
設(shè)置響應(yīng)頭部信息
app.use(function(req, res, next) { //允許跨域 CORS res.setHeader("Access-Control-Allow-Origin", "*"); //緩存設(shè)置 res.setHeader("Cache-Control", "no-cache"); next(); });
設(shè)置get請(qǐng)求url對(duì)應(yīng)的處理函數(shù)(獲取評(píng)論json數(shù)據(jù))
app.get("/api/comments", function(req, res) { //讀取comments.json文件,并且解析為json數(shù)據(jù) fs.readFile(COMMENTS_FILE, function(err, data) { if (err) { console.error(err); process.exit(1); } //讀取成功后,返回 res.json(JSON.parse(data)); }); });
設(shè)置post請(qǐng)求url對(duì)應(yīng)的處理函數(shù)(提交評(píng)論數(shù)據(jù))
app.post("/api/comments", function(req, res) { //先讀取comments.json文件 fs.readFile(COMMENTS_FILE, function(err, data) { if (err) { console.error(err); process.exit(1); } //將文件內(nèi)容解析為json數(shù)據(jù) var comments = JSON.parse(data); //獲取新評(píng)論 var newComment = { id: Date.now(), author: req.body.author, text: req.body.text, }; //添加json數(shù)組中 comments.push(newComment); //將json數(shù)據(jù)寫回到comments.json文件中,并且返回全部的評(píng)論數(shù)據(jù) fs.writeFile(COMMENTS_FILE, JSON.stringify(comments, null, 4), function(err) { if (err) { console.error(err); process.exit(1); } res.json(comments); }); }); });
啟動(dòng),監(jiān)聽端口
app.listen(app.get("port"), function() { console.log("Server started: http://localhost:" + app.get("port") + "/"); });web端
web端核心在于example.js文件,結(jié)合官網(wǎng)的資料,我們對(duì)這個(gè)應(yīng)用進(jìn)行分析,學(xué)習(xí)如何構(gòu)建一個(gè)簡(jiǎn)單的react應(yīng)用。
組件結(jié)構(gòu)React踐行了Web Components的理念,依照組件化的開發(fā)方式,我們來(lái)分析這個(gè)應(yīng)用的組件結(jié)構(gòu)(如圖所示):
即是:
-- CommentBox -- CommentList -- Comment -- CommentForm
組件之間的關(guān)系圖為:
組件Comment如上述的結(jié)構(gòu)圖,我們從最底層開始編寫組件Comment,這個(gè)組件需要做兩件事情
接收上層組件CommentList傳遞的數(shù)據(jù),動(dòng)態(tài)渲染虛擬DOM節(jié)點(diǎn),則從props中讀取數(shù)據(jù)
//評(píng)論人 {this.props.author} //評(píng)論的內(nèi)容 {this.props.children}
由于評(píng)論是支持MarkDown語(yǔ)法的,因此需要使用第三放庫(kù)marked對(duì)用戶輸入的內(nèi)容進(jìn)行處理。
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
此外,輸出的內(nèi)容要解析為HTML,而在默認(rèn)情況下,基于預(yù)防XSS攻擊的考慮,React對(duì)輸出的內(nèi)容是不解析為HTML的。此時(shí),需要利用到特殊的屬性dangerouslySetInnerHTML,要將內(nèi)容放到一個(gè)對(duì)象的_html屬性中,然后將這個(gè)對(duì)象賦值給dangerouslySetInnerHTML屬性
var html = {_html:"輸出的html內(nèi)容"};
var Comment = React.createClass({ rawMarkup : function() { var rawMarkup = marked(this.props.children.toString(),{sanitize:true}); return {_html : rawMarkup}; //React的規(guī)則,會(huì)讀取這個(gè)對(duì)象的_html內(nèi)容, }, render : function() { return (組件CommentList); } });{this.props.author}
組件CommentList需要做的就是接收上一層組件CommentBox傳遞過(guò)來(lái)的數(shù)據(jù),然后根據(jù)數(shù)據(jù)生成多個(gè)子組件Comment
var CommentList = React.createClass({ render : function() { var commentNodes = this.props.data.map(function(comment){ return ({comment.text} ); }); return ({commentNodes}); } })
在生成子組件Comment時(shí),將每個(gè)子組件的key屬性設(shè)置為comment.id,這是因?yàn)?b>key是一個(gè)可選的唯一標(biāo)識(shí)符,通過(guò)它可以給組件設(shè)置一個(gè)獨(dú)一無(wú)二的鍵,并確保它在一個(gè)渲染周期中保持一致,使得React能夠更加智能地決定應(yīng)該重用一個(gè)組件,還是銷毀并重新創(chuàng)建一個(gè)組件,進(jìn)而提升渲染性能。
組件CommentForm組件CommentForm需要做的就是兩件事情
管理自身的狀態(tài)this.state(即表單中輸入的評(píng)論人和評(píng)論內(nèi)容)
當(dāng)表單輸入發(fā)生變化時(shí)
當(dāng)表單提交時(shí)
當(dāng)submit事件觸發(fā)時(shí),調(diào)用上一層組件CommentBox的事件處理函數(shù),改變組件CommentBox的狀態(tài)。
var CommentForm = React.createClass({ getInitialState : function() { //設(shè)置初始狀態(tài), return {author:"",text:""}; }, handleAuthorChange : function(e) { this.setState({ author : e.target.value }); }, handleTextChange : function(e) { this.setState({ text : e.target.value }); }, handleSubmit : function(e) { e.preventDefault(); var author = this.state.author.trim(); var text = this.state.text.trim(); if(!text || !author){ //為空驗(yàn)證 return; } //觸發(fā)評(píng)論提交事件,改變父組件的狀態(tài) this.props.onCommentSubmit({author:author,text:text}); //改變自身的狀態(tài) this.setState({author:"",text:""}); } });
在這里有一個(gè)值得注意的點(diǎn),那就是抽象的自定義事件commentSubmit和真實(shí)的事件submit之間的聯(lián)系,這是一個(gè)相當(dāng)實(shí)用的技巧,在接下來(lái)的章節(jié)可以看到是如何實(shí)現(xiàn)的。
組件CommentBox作為整個(gè)應(yīng)用的頂層組件,CommentBox需要做的事情有:
從服務(wù)器端請(qǐng)求已有的評(píng)論數(shù)據(jù)
將新的評(píng)論數(shù)據(jù)上傳到服務(wù)器
管理自身的狀態(tài),根據(jù)狀態(tài)對(duì)視圖進(jìn)行渲染(狀態(tài)改變的示意圖如下)
var CommentBox = React.createClass({ getInitialState : function(){ return {data : []}; }, loadCommentsFromServer : function() { //使用了jQuery的Ajax $.ajax({ url : this.props.url, dataType : "json", cache : false, success : function(data) { this.setState({data:data}); }.bind(this), error : function(xhr,status,err){ console.err(this.props.url,status,err.toString()); }.bind(this) }); }, componentDidMount : function() { /* 這個(gè)方法屬于React組件生命周期方法,在render方法成功調(diào)用并且真實(shí)的DOM 已經(jīng)渲染之后,調(diào)用此方法,這個(gè)方法發(fā)送json數(shù)據(jù)請(qǐng)求,并且設(shè)置一個(gè)定時(shí)器 ,每隔一段時(shí)間就向服務(wù)器請(qǐng)求數(shù)據(jù) */ this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer,this.props.pollInterval); }, handleCommentSubmit : function(comment) { /* 這個(gè)方法也是比較有意思: 1. 自定義了一個(gè)commentSubmit事件,并且此方法作為該事件的處理函數(shù)。 2. 此方法是在子組件CommentForm的submit事件處理函數(shù)中調(diào)用 */ var comments = this.state.data; comment.id = Date.now(); var newComments = comments.concat([comment]); //改變自身狀態(tài) 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) { //還原數(shù)據(jù) this.setState({data:comments}); console.err(this.props.url,status,err.toString()); }.bind(this) }); }, render : function() { return (); } });Comments
最后,只需將組件CommentBox掛載到真實(shí)的DOM節(jié)點(diǎn)上,就可以看到效果了
ReactDOM.render(, document.getElementById("content") );
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79605.html
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。插....
摘要:在上面的列表中,是自解釋型的。我們將使用后者。調(diào)整文件的內(nèi)容到這一步,這個(gè)應(yīng)用就具備熱刷新的功能。下一步,更新文件中的到現(xiàn)在為止,如果你在控制臺(tái)運(yùn)行壓縮文件將被創(chuàng)建并且放在路徑下面。 這是React和ECMAScript2015系列文章的最后一篇,我們將繼續(xù)探索React 和 Webpack的使用。 下面是所有系列文章章節(jié)的鏈接: React 、 ES6 - 介紹(第一部分) Rea...
閱讀 3136·2021-11-11 16:54
閱讀 2291·2021-09-04 16:48
閱讀 3219·2019-08-29 16:08
閱讀 642·2019-08-29 15:13
閱讀 1344·2019-08-29 15:09
閱讀 2660·2019-08-29 12:45
閱讀 1926·2019-08-29 12:12
閱讀 444·2019-08-26 18:27