這篇文章主要講述的就是關於react的工作原理介紹,內容有工作原理的具體流程,現在讓我們一起來看這篇文章吧
現在最熱門的前端框架有AngularJS、 React、Bootstrap等。自從接觸了ReactJS,ReactJs的虛擬DOM(Virtual DOM)和組件化的開發深深的吸引了我,下面來跟我一起領略ReactJs的風采吧~~ 文章有點長,耐心讀完,你會有很大收穫哦~
一、ReactJS簡介
React 起源於Facebook 的內部項目,因為該公司對市場上所有JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設Instagram 的網站。做出來以後,發現這套東西很好用,就在2013年5月就開源了。由於 React 的設計想法極為獨特,屬於革命性創新,但性能出眾,程式碼邏輯卻非常簡單。所以,越來越多的人開始注意和使用,認為它可能是未來 Web 發展的主流工具。
二、對ReactJS的認知及ReactJS的優點
首先,對於React,有一些認識誤區,這裡先總結一下:
React不是完整的MVC框架,最多可以認為是MVC中的V(View),甚至React並不非常認可MVC開發模式;
React的伺服器端Render能力只能算是錦上添花的功能,並不是其核心出發點,事實上React官方網站幾乎沒有提及其在伺服器端的應用;
有人拿React和Web Component相提並論,但兩者並不是完全的競爭關係,你完全可以用React去開發一個真正的Web Component;
React不是一個新的模板語言,JSX只是一個表象,沒有JSX的React也能運作。
1、ReactJS的背景和原理
在Web開發中,我們總需要將變化的資料即時反應到UI上,這時就需要對DOM進行操作。而複雜或頻繁的DOM操作通常是效能瓶頸產生的原因(如何進行高效能的複雜DOM操作通常是衡量一個前端開發人員技能的重要指標)。 React為此引進了虛擬DOM(Virtual DOM)的機制:在瀏覽器端用Javascript實作了一套DOM API。基於React進行開發時所有的DOM構造都是透過虛擬DOM進行,每當資料變化時,React都會重新建構整個DOM樹,然後React將目前整個DOM樹和上一次的DOM樹進行對比,得到DOM結構的區別,然後僅將需要變化的部分進行實際的瀏覽器DOM更新。而且React能夠批次虛擬DOM的刷新,在一個事件循環(Event Loop)內的兩次資料變化會被合併,例如你連續的先將節點內容從A變成B,然後又從B變成A,React會認為UI不會發生任何變化,而如果透過手動控制,這種邏輯通常是極為複雜的。儘管每一次都需要建構完整的虛擬DOM樹,但是因為虛擬DOM是內存數據,性能是極高的,而對實際DOM進行操作的僅僅是Diff部分,因而能達到提高性能的目的。這樣,在確保效能的同時,開發者將不再需要關注某個資料的變化如何更新到一個或多個特定的DOM元素,而只需要關心在任意一個資料狀態下,整個介面是如何Render的。
如果你像在90年代那樣寫過伺服器端Render的純Web頁面那麼應該知道,伺服器端要做的就是根據資料Render出HTML送到瀏覽器端。如果這時因為使用者的一個點擊需要改變某個狀態文字,那麼也是透過刷新整個頁面來完成的。伺服器端並不需要知道是哪一小段HTML發生了變化,而只需要根據資料刷新整個頁面。換句話說,任何UI的變化都是透過整體刷新來完成的。而React將這種開發模式以高效能的方式帶到了前端,每做一點介面的更新,你都可以認為刷新了整個頁面。至於如何進行局部更新以確保效能,則是React框架要完成的事情。
借用Facebook介紹React的影片中聊天應用程式的例子,當一條新的訊息過來時,傳統開發的思路如上圖,你的開發過程需要知道哪條資料過來了,如何將新的DOM結點加入到目前DOM樹上;而基於React的開發想法如下圖,你永遠只需要關心資料整體,兩次資料之間的UI如何變化,則完全交給框架去做。可以看到,使用React大大降低了邏輯複雜性,這意味著開發難度降低,可能產生Bug的機會也更少。
2、元件化
虛擬DOM(virtual-dom)不僅帶來了簡單的UI開發邏輯,同時也帶來了元件化開發的思想,所謂元件,即封裝起來的具有獨立功能的UI部件。 React推薦以元件的方式去重新思考UI構成,將UI上每一個功能相對獨立的模組定義成元件,然後將小的元件透過組合或嵌套的方式構成大的元件,最終完成整體UI的建構。例如,Facebook的instagram.com整站都採用了React來開發,整個頁面就是一個大的組件,其中包含了嵌套的大量其它組件,大家有興趣可以看下它背後的程式碼。
如果說MVC的想法讓你做到視圖-資料-控制器的分離,那麼元件化的思考方式則是帶來了UI功能模組之間的分離。我們透過一個典型的Blog評論介面來看MVC和組件化開發思路的差異。
對於MVC開發模式來說,開發者將三者定義成不同的類,實現了表現,數據,控制的分離。開發者更多的是從技術的角度來對UI進行拆分,實現鬆散耦合。
對於React而言,則完全是一個新的思路,開發者從功能的角度出發,將UI分成不同的元件,每個元件都獨立封裝。
在React中,你按照介面模組自然劃分的方式來組織和編寫你的程式碼,對於評論介面而言,整個UI是一個透過小元件構成的大元件,每個元件只關心自己部分的邏輯,彼此獨立。
React認為一個元件應該具有以下特徵:
(1)可組合(Composeable):一個元件易於和其它元件一起使用,或嵌套在另一個元件內部。如果一個元件內部創建了另一個元件,那麼說父元件擁有(own)它所建立的子元件,透過這個特性,一個複雜的UI可以分割成多個簡單的UI元件;
( 2)可重複使用(Reusable):每個元件都是具有獨立功能的,它可以被使用在多個UI場景;
(3)可維護(Maintainable):每個小的元件僅包含自身的邏輯,更容易被理解和維護;
二、下載ReactJS,寫Hello,world
ReactJs下載非常簡單,為了方便大家下載,這裡再一次給出下載地址http://facebook.github.io/react/downloads.html,下載完成後,我麼看到的是一個壓縮包。解壓縮後,我們新建一個html文件,引用react.js和JSXTransformer.js這兩個js檔案。 html模板如下(js路徑改成自己的):
nbsp;html> <script></script> <script></script> <p></p> <script> // ** Our code goes here! ** </script>
這裡大家可能會奇怪,為什麼script的type是text/jsx,這是因為 React 獨有的 JSX 語法,跟 JavaScript 不相容。凡是使用 JSX 的地方,都要加上 type="text/jsx" 。其次,React 提供兩個函式庫: react.js 和 JSXTransformer.js ,它們必須先載入。其中,JSXTransformer.js 的作用是將 JSX 語法轉換為 JavaScript 文法.這一步很消耗時間,實際上線的時候,應該要將它放到伺服器完成。 (想看更多就到PHP中文網React參考手冊欄位中學習)
到這裡我們就可以開始寫程式碼了,首先我們先來認識一下ReactJs裡面的React.render方法:
React.render 是React 最基本的方法,用於將範本轉換為HTML 語言,並插入指定的DOM 節點。
下面我們在script標籤裡面寫程式碼,來輸出Hello,world,程式碼如下:
React.render( <h1>Hello, world!</h1>, document.getElementById('container') );
var names = ['Jack', 'Tom', 'Alice']; React.render( <p> { names.map(function (name) { return </p><p>Hello, {name}!</p> }) } , document.getElementById('container') );这里我们声明了一个names数组,然后遍历在前面加上Hello,输出到DOM中,输出结果如下:JSX 允許直接在範本中插入JavaScript 變數。如果這個變數是數組,則會展開這個數組的所有成員,程式碼如下:
var arr = [ <h1>Hello world!</h1>, <h2>React is perfect!</h2>, ]; React.render( <p>*{arr}*</p>, document.getElementById('container') );顯示結果如下: 這裡的星號只是做標識用的,大家不要被她迷惑了~~ 你看到這裡,說明你對React還是蠻感興趣的,恭喜你,堅持下來了,那麼下面,我們開始學習React裡面的"真功夫"了~~ Are you ready?
四、ReactJS组件
1、组件属性
前面说了,ReactJS是基于组件化的开发,下面我们开始来学习ReactJS里面的组件,React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。
下面,我们来编写第一个组件Greet,有一个name属性,然后输出hello + name的值,代码如下:
var Greet = React.createClass({ render: function() { return <h1>Hello {this.props.name}</h1>; } }); React.render( <greet></greet>, document.getElementById('container') );
看到这段代码,接触过AngularJS的朋友们是不是有一种熟悉的感觉,不过这里有几点需要注意:
1、获取属性的值用的是this.props.属性名
2、创建的组件名称首字母必须大写。
3、为元素添加css的class时,要用className.
4、组件的style属性的设置方式也值得注意,要写成style={{width: this.state.witdh}}
2、组件状态
组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI 。下面我们来编写一个小例子,一个文本框和一个button,通过点击button可以改变文本框的编辑状态,禁止编辑和允许编辑。通过这个例子来理解ReactJS的状态机制。先看代码:
var InputState = React.createClass({ getInitialState: function() { return {enable: false}; }, handleClick: function(event) { this.setState({enable: !this.state.enable}); }, render: function() { return ( <p> <input> <button>Change State</button> </p> ); } }); React.render( <inputstate></inputstate>, document.getElementById('container') );
这里,我们又使用到了一个方法getInitialState,这个函数在组件初始化的时候执行,必需返回NULL或者一个对象。这里我们可以通过this.state.属性名来访问属性值,这里我们将enable这个值跟input的disabled绑定,当要修改这个属性值时,要使用setState方法。我们声明handleClick方法,来绑定到button上面,实现改变state.enable的值.效果如下:
原理分析:
当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。
这里值得注意的几点如下:
1、getInitialState函数必须有返回值,可以是NULL或者一个对象。
2、访问state的方法是this.state.属性名。
3、变量用{}包裹,不需要再加双引号。
3、组件的生命周期
组件的生命周期分成三个状态:
Mounting:已插入真实 DOM
Updating:正在被重新渲染
Unmounting:已移出真实 DOM
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
下面来看一个例子:
var Hello = React.createClass({ getInitialState: function () { return { opacity: 1.0 }; }, componentDidMount: function () { this.timer = setInterval(function () { var opacity = this.state.opacity; opacity -= .05; if (opacity Hello {this.props.name} ); } }); React.render( <hello></hello>, document.body );
上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。
4、组件的嵌套
React是基于组件化的开发,那么组件化开发最大的优点是什么?毫无疑问,当然是复用,下面我们来看看React中到底是如何实现组件的复用的,这里我们还写一个例子来说吧,代码如下:
var Search = React.createClass({ render: function() { return ( <p> {this.props.searchType}:<input> <button>Search</button> </p> ); } }); var Page = React.createClass({ render: function() { return ( <p> </p><h1>Welcome!</h1> <search></search> <search></search> ); } }); React.render( <page></page>, document.getElementById('container') );
这里我们创建了一个Search组件,然后又创建了一个Page组件,然后我们在Page组件中调用Search组件,并且调用了两次,这里我们通过属性searchType传入值,最终显示结果如图:
五、ReactJs小结
关于ReactJS今天就先学习到这里了,下面来总结一下,主要有以下几点:
1、ReactJs是基于组件化的开发,所以最终你的页面应该是由若干个小组件组成的大组件。
2、可以通过属性,将值传递到组件内部,同理也可以通过属性将内部的结果传递到父级组件(留给大家研究);要对某些值的变化做DOM操作的,要把这些值放到state中。
3、为组件添加外部css样式时,类名应该写成className而不是class;添加内部样式时,应该是style={{opacity: this.state.opacity}}而不是style="opacity:{this.state.opacity};"。
4、组件名称首字母必须大写。
5、变量名用{}包裹,且不能加双引号。
六、ReactJS优缺点
优点:
React速度很快
與其它框架相比,React採取了一種特立獨行的操作DOM的方式。
它不會直接對DOM進行操作。
它引進了一個叫做虛擬DOM的概念,安插在JavaScript邏輯和實際的DOM之間。
這概念提高了Web效能。在UI渲染過程中,React透過在虛擬DOM中的微操作來實對現實際DOM的局部更新。
跨瀏覽器相容
虛擬DOM幫助我們解決了跨瀏覽器問題,它為我們提供了標準化的API,甚至在IE8中都是沒問題的。
模組化
為你程式編寫獨立的模組化UI元件,這樣當某個或某些元件出現問題是,可以方便地進行隔離。
每個元件都可以進行獨立的開發和測試,並且它們可以引入其它組件。這等同於提高了程式碼的可維護性。
單向資料流讓事情一目了然
Flux是用於在JavaScript應用程式中建立單向資料層的架構,它隨著React視圖庫的開發而被Facebook概念化。它只是一個概念,而非特定工具的實作。它可以被其它框架吸收。例如,Alex
Rattray有一個很好的Flux實例,在React中使用了Backbone的集合和模型。
純粹的JavaScript
現代網路應用程式與傳統的網路應用程式有著不同的工作方式。
例如,視圖層的更新需要透過使用者互動而不需要請求伺服器。因此視圖和控制器非常依賴彼此。
許多框架使用Handlebars或Mustache等範本引擎來處理視圖層。但React相信視圖和控制器應該相互依賴而不是使用第三方模板引擎,而且,最重要的是,它是純粹的JavaScript程式。
同構的JavaScript
單一頁面JS應用程式的最大缺陷在於搜尋引擎的索引有很大限制。 React對此有了解決方案。
React可以在伺服器上預先渲染應用程式再傳送到客戶端。它可以從預先渲染的靜態內容中恢復相同的記錄到動態應用程式中。
因為搜尋引擎的爬蟲程式依賴的是服務端回應而不是JavaScript的執行,預先渲染你的應用程式有助於搜尋引擎優化。
React與其它框架/函式庫相容性好
例如使用RequireJS來載入和打包,而Browserify和Webpack適用於建立大型應用。它們使得那些艱難的任務不再讓人望而生畏。
缺點?
React本身只是一個V而已,所以如果是大型專案想要一套完整的框架的話,也許還需要引入Flux和routing相關的東西。
大多數坑沒踩出來
這篇文章到這就結束了(想看更多就到PHP中文網React使用手冊欄位學習),有問題的可以在下方留言提問。
以上是react的工作原理是什麼? react的工作原理的具體介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!