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