摘要:原文地址是一個(gè)庫(kù),主要是通過(guò)操作數(shù)據(jù)的方式去操縱,為什么要重造輪子呢,因?yàn)橛X(jué)的目前市面上的框架對(duì)于創(chuàng)建大型應(yīng)用程序不夠直觀,不能滿足需求,所以誕生了。其實(shí)說(shuō)它性能高,只不過(guò)是用的方式計(jì)算出最小的操作,所以性能就上來(lái)了。
原文地址:https://gmiam.com/post/react-...
React 是一個(gè) JS 庫(kù),主要是通過(guò)操作數(shù)據(jù)的方式去操縱 DOM,為什么要重造輪子呢,因?yàn)?FB 覺(jué)的目前市面上的 MV* 框架對(duì)于創(chuàng)建大型應(yīng)用程序不夠直觀,不能滿足需求,所以誕生了 React。
React 現(xiàn)在官方的介紹是 Declarative、Component-Based、Learn Once, Write Anywhere,其實(shí)開(kāi)始推出時(shí)主要的特色是 Virtual DOM,因?yàn)?DOM 操作總是很慢的,而 JS 的性能日趨向上,所以 React 內(nèi)部用 JS 維護(hù)一顆 DOM 樹(shù),每次數(shù)據(jù)變了從新生成一顆樹(shù)與之前的做對(duì)比,把實(shí)際變化的地方應(yīng)用到真實(shí)的 DOM 上。其實(shí)說(shuō)它性能高,只不過(guò)是用 JS 的方式計(jì)算出最小的 DOM 操作,所以性能就上來(lái)了。
說(shuō)到這里我們實(shí)際操作下吧,這里假設(shè)你熟悉 node、babel、webpack 方式,當(dāng)然你也可以選擇你喜好的方式 傳送門
首先創(chuàng)建目錄結(jié)構(gòu)
react-demo .babelrc index.html src app.js
index.html
React App
app.js
var React = require( "react" ) var ReactDOM = require( "react-dom" ) var HelloMessage = React.createClass( { render: function () { returnHello {this.props.name}} }) ReactDOM.render(, document.getElementById( "app" ) )
.babelrc
{ "presets": ["es2015","react"] }
安裝依賴 npm install --save react react-dom babel-preset-react babel-loader babel-core
編譯監(jiān)聽(tīng) webpack src/app.js bundle.js -w --module-bind "js=babel"
打開(kāi) index.html 查看效果
先說(shuō)下 jsx 語(yǔ)法,React 讓你不需要再寫 html 拼接字符等操作,而是直接寫 html,js 處理放到 { } 里書(shū)寫,官方提供 jsx 語(yǔ)法非必要,也可以脫離寫純 js 的,如上面的經(jīng)過(guò)編譯后
"use strict"; var HelloMessage = React.createClass({ displayName: "HelloMessage", render: function render() { return React.createElement( "div", null, "Hello ", this.props.name ); } }); ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), document.getElementById( "app" ));
但是可以看出這么麻煩沒(méi)人去手寫的
再來(lái)說(shuō)下組件,React 的概念就是給應(yīng)用分層,創(chuàng)建一個(gè)個(gè)組件,最后拼出一個(gè)頁(yè)面,組件方便后期的維護(hù)、擴(kuò)展、以及再重用,隨著組件的越多后面寫的代碼越少,來(lái)個(gè)例子
var Avatar = React.createClass({ render: function() { return (); } }); var PagePic = React.createClass({ render: function() { return ( ); } }); var PageLink = React.createClass({ render: function() { return ( {this.props.pagename} ); } }); ReactDOM.render(, document.getElementById("app") );
可以看到組件要提供自己的 render 方法,組件可以相互嵌套,數(shù)據(jù)通過(guò) this.props 單向傳遞
同時(shí)需要注意
屬性 class 要寫成 className,for 寫成 htmlFor,因?yàn)樗鼈兪?js 的保留字
對(duì)于render 返回的內(nèi)容只能有一個(gè)頂級(jí)標(biāo)簽,如果標(biāo)簽超過(guò)多行要用 ( ) 包含
關(guān)于 props 不要去改變它,會(huì)導(dǎo)致一些不可預(yù)知的問(wèn)題,另外官方推薦用 es6 的 ... 操作符去掛載屬性
var props = { foo: "default", bar:"bar" }; var component =; console.log(component.props.bar); // "bar" console.log(component.props.foo); // "override"
這里有個(gè)特殊屬性 this.props.children,來(lái)個(gè)例子
var NotesList = React.createClass({ propTypes: { children: React.PropTypes.array.isRequired, }, render: function() { return ({ React.Children.map(this.props.children, function (child) { return
); } }); ReactDOM.render(- {child}
; }) }hello world , document.getElementById("app") );
同時(shí)可以看到這里提供了 propTypes 可以給屬性做檢查,驗(yàn)證說(shuō)明 children 必須提供且是一個(gè)數(shù)組(多個(gè)),更多的類型驗(yàn)證可以 看這里
前面創(chuàng)建組件都是通過(guò) React.createClass ,可以通過(guò) es6 class 語(yǔ)法
class HelloMessage extends React.Component { render() { returnHello {this.props.name}; } } ReactDOM.render(, document.getElementById("app"));
還有 Stateless Functions 方式
function HelloMessage(props) { returnHello {props.name}; } ReactDOM.render(, document.getElementById("app"));
官方推薦盡量寫 stateless functions ,因?yàn)槲磥?lái)會(huì)優(yōu)化這些來(lái)避免無(wú)用的檢查和內(nèi)存分配
下面看下如何寫事件
var Input = React.createClass({ getInitialState: function() { return {value: "Hello!"}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function () { var value = this.state.value; return (); } }); ReactDOM.render(, document.getElementById("app"));{value}
駱駝式的 on 語(yǔ)法即可監(jiān)聽(tīng)事件,事件是標(biāo)準(zhǔn)的跨瀏覽器的事件,雖然內(nèi)聯(lián)寫法,但是是委托實(shí)現(xiàn)的~
說(shuō)到了事件交互可能就要設(shè)及獲取真實(shí)的 dom 節(jié)點(diǎn),React 通過(guò) ref 設(shè)置,來(lái)個(gè)例子
var React = require( "react" ) var ReactDOM = require( "react-dom" ) var MyComponent = React.createClass({ handleClick: function() { this.refs["myinput"].focus() }, render: function() { return (); } }); ReactDOM.render(, document.getElementById("app") );
ref 字符屬性的方式未來(lái)會(huì)被廢棄,官方推薦使用 ref callback 方式
var MyComponent = React.createClass({ handleClick: function() { if (this.myTextInput !== null) { this.myTextInput.focus(); } }, render: function() { return (this.myTextInput = ref} />); } }); ReactDOM.render(, document.getElementById("app") );
說(shuō)到這里看下組件的生命周期與如何更新,還是來(lái)個(gè)例子
var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return (Seconds Elapsed: {this.state.secondsElapsed}); } }); ReactDOM.render(, document.getElementById("app"));
生命周期有三個(gè)主要部分
Mounting 插入 dom
getInitialState()
componentWillMount()
componentDidMount ()
Updating 重新渲染
componentWillReceiveProps(object nextProps)
shouldComponentUpdate(object nextProps, object nextState)
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
Unmounting 移除 dom
componentWillUnmount()
周期提供了 will 方法在事情發(fā)生之前調(diào)用, did 方法在事情法神之后調(diào)用,具體查看這里
對(duì)于更新,上面的例子在組件 componentDidMount (插入 dom 后) hook 中定時(shí)更新組件的 state,state變更會(huì)導(dǎo)致 render 重新渲染頁(yè)面
對(duì)于這里說(shuō)下性能問(wèn)題,雖然虛擬dom計(jì)算過(guò)程很快,但是很多時(shí)候我們可以避免它的計(jì)算以更好的優(yōu)化處理
例如 一個(gè)組件的更新可能會(huì)導(dǎo)致它的子組件一起跟著更新,子組件很可能沒(méi)有變化,但同樣會(huì)進(jìn)行一次diff運(yùn)算,白白浪費(fèi)了時(shí)間,所以 React 提供了 shouldComponentUpdate 鉤子函數(shù),默認(rèn)是直接返回 true,也及是每次都運(yùn)算比較,所以我們可以在這里優(yōu)化,來(lái)個(gè)例子
React.createClass({ propTypes: { value: React.PropTypes.string.isRequired }, shouldComponentUpdate: function(nextProps, nextState) { return this.props.value !== nextProps.value; }, render: function() { return{this.props.value}; } });
這里只有 value 變化的時(shí)候在重新渲染計(jì)算,否則直接跳過(guò)
對(duì)于上面的淺對(duì)比,React 提供了通用解決方案 PureRenderMixin 擴(kuò)展,應(yīng)用 React 的 mixins 功能即可自動(dòng)實(shí)現(xiàn)處理比對(duì)
var PureRenderMixin = require("react-addons-pure-render-mixin"); React.createClass({ mixins: [PureRenderMixin], render: function() { return{this.props.value}; } });
但是如果有深層結(jié)構(gòu),上面的處理可能不會(huì)按預(yù)期工作,例如
// this.props.value 的值為 { foo: "bar" } // nextProps.value 的值為 { foo: "bar" }, // 但是對(duì)象的引用不同,導(dǎo)致不會(huì)相等 this.props.value !== nextProps.value; // true
而且如果我們不小心管理引用的話也會(huì)引發(fā)另一些問(wèn)題,例如這個(gè)組件有一個(gè)父組件
React.createClass({ getInitialState: function() { return { value: { foo: "bar" } }; }, onClick: function() { var value = this.state.value; value.foo += "bar"; // ANTI-PATTERN! this.setState({ value: value }); }, render: function() { return ( ); } });
首先內(nèi)部組件得到 { foo: "bar" },點(diǎn)擊后出發(fā) value 更新 { foo: "barbar" },觸發(fā) re-rendering 程序,內(nèi)部組件將會(huì)得到 { foo: "barbar" },但是 this.props.value 與 nextProps.value 指向同一個(gè)引用,導(dǎo)致任何時(shí)候比對(duì)都是 true,而導(dǎo)致頁(yè)面不更新
而且如果父組件應(yīng)用 PureRenderMixin 的話,由于改動(dòng)相同引用所以也會(huì)導(dǎo)致父組件的 re-rendering 不觸發(fā)
那最后該如何處理呢?請(qǐng)看下一篇 Immutable-js 來(lái)解救你~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80396.html
摘要:前言寫此系列博客的目的是對(duì)所學(xué)知識(shí)點(diǎn)的總結(jié)和梳理,包括填坑方案分享,希望能幫助到還并不會(huì)使用的開(kāi)發(fā)者入門官方文檔中文文檔社區(qū)項(xiàng)目搭建按照官方提供的搭建項(xiàng)目全局安裝或全局安裝后可以使用這條命令創(chuàng)建名為的項(xiàng)目啟動(dòng) 前言 寫此系列博客的目的是對(duì)所學(xué)React知識(shí)點(diǎn)的總結(jié)和梳理,包括填坑方案分享,希望能幫助到還并不會(huì)使用React的開(kāi)發(fā)者入門React React官方文檔React中文文檔R...
摘要:系列種優(yōu)化頁(yè)面加載速度的方法隨筆分類中個(gè)最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁(yè)性能管理詳解離線緩存簡(jiǎn)介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問(wèn)性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對(duì)象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁(yè)面加載速度的方法 隨筆分類 - HTML5 HTML5中40個(gè)最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁(yè)性能管理詳解 HTML5 ...
摘要:系列種優(yōu)化頁(yè)面加載速度的方法隨筆分類中個(gè)最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁(yè)性能管理詳解離線緩存簡(jiǎn)介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問(wèn)性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對(duì)象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁(yè)面加載速度的方法 隨筆分類 - HTML5 HTML5中40個(gè)最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁(yè)性能管理詳解 HTML5 ...
摘要:特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 特意對(duì)前端學(xué)習(xí)資源做一個(gè)匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進(jìn)步。 本以為自己收藏的站點(diǎn)多,可以很快搞定,沒(méi)想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補(bǔ)充。有錯(cuò)誤的地方,還請(qǐng)斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會(huì)及時(shí)更新,平時(shí)業(yè)務(wù)工作時(shí)也會(huì)不定期更...
閱讀 2493·2019-08-30 15:52
閱讀 2288·2019-08-30 12:51
閱讀 2877·2019-08-29 18:41
閱讀 2867·2019-08-29 17:04
閱讀 885·2019-08-29 15:11
閱讀 1806·2019-08-28 18:02
閱讀 3646·2019-08-26 10:22
閱讀 2557·2019-08-26 10:12