React的四個(gè)概念簡(jiǎn)單介紹
React主要有四個(gè)主要概念構(gòu)成,下面分別來(lái)介紹一下:
Virtual DOM
- 虛擬DOM是React的基石。
- 之所以引入虛擬DOM,一方面是性能的考慮。Web應(yīng)用和網(wǎng)站不同,一個(gè)Web應(yīng)用 中通常會(huì)在單頁(yè)內(nèi)有大量的DOM操作,而這些DOM操作很慢。
- 在React中,應(yīng)用程序在虛擬DOM上操作,這讓React有了優(yōu)化的機(jī)會(huì)。簡(jiǎn)單說, React在每次需要渲染時(shí),會(huì)先比較當(dāng)前DOM內(nèi)容和待渲染內(nèi)容的差異, 然后再?zèng)Q定如何最優(yōu)地更新DOM。這個(gè)過程被稱為reconciliation。
- 除了性能的考慮,React引入虛擬DOM更重要的意義是提供了一種一致的開發(fā)方 式來(lái)開發(fā)服務(wù)端應(yīng)用、Web應(yīng)用和手機(jī)端應(yīng)用:

因?yàn)橛辛颂摂MDOM這一層,所以通過配備不同的渲染器,就可以將虛擬DOM的內(nèi)容 渲染到不同的平臺(tái)。而應(yīng)用開發(fā)者,使用JavaScript就可以通吃各個(gè)平臺(tái)了。相當(dāng)棒的思路!
- Virtual DOM速度快的說明
在Web開發(fā)中,我們總需要將變化的數(shù)據(jù)實(shí)時(shí)反應(yīng)到UI上,這時(shí)就需要對(duì)DOM進(jìn)行操作。而復(fù)雜或頻繁的DOM操作通常是性能瓶頸產(chǎn)生的原因(如何 進(jìn)行高性能的復(fù)雜DOM操作通常是衡量一個(gè)前端開發(fā)人員技能的重要指標(biāo))。React為此引入了虛擬DOM(Virtual DOM)的機(jī)制:在瀏覽器端用Javascript實(shí)現(xiàn)了一套DOM API。基于React進(jìn)行開發(fā)時(shí)所有的DOM構(gòu)造都是通過虛擬DOM進(jìn)行,每當(dāng)數(shù)據(jù)變化時(shí),React都會(huì)重新構(gòu)建整個(gè)DOM樹,然后React將當(dāng)前 整個(gè)DOM樹和上一次的DOM樹進(jìn)行對(duì)比,得到DOM結(jié)構(gòu)的區(qū)別,然后僅僅將需要變化的部分進(jìn)行實(shí)際的瀏覽器DOM更新。而且React能夠批處理虛擬 DOM的刷新,在一個(gè)事件循環(huán)(Event Loop)內(nèi)的兩次數(shù)據(jù)變化會(huì)被合并,例如你連續(xù)的先將節(jié)點(diǎn)內(nèi)容從A變成B,然后又從B變成A,React會(huì)認(rèn)為UI不發(fā)生任何變化,而如果通過手動(dòng)控 制,這種邏輯通常是極其復(fù)雜的。盡管每一次都需要構(gòu)造完整的虛擬DOM樹,但是因?yàn)?strong>虛擬DOM是內(nèi)存數(shù)據(jù),性能是極高的,而對(duì)實(shí)際DOM進(jìn)行操作的僅僅是 Diff部分,因而能達(dá)到提高性能的目的。這樣,在保證性能的同時(shí),開發(fā)者將不再需要關(guān)注某個(gè)數(shù)據(jù)的變化如何更新到一個(gè)或多個(gè)具體的DOM元素,而只需要 關(guān)心在任意一個(gè)數(shù)據(jù)狀態(tài)下,整個(gè)界面是如何Render的。詳情查看
React組件
- 組件化概念
- 虛擬DOM(virtual-dom)不僅帶來(lái)了簡(jiǎn)單的UI開發(fā)邏輯,同時(shí)也帶來(lái)了組件化開發(fā)的思想,所謂組件,即封裝起來(lái)的具有獨(dú)立功能的UI部 件。React推薦以組件的方式去重新思考UI構(gòu)成,將UI上每一個(gè)功能相對(duì)獨(dú)立的模塊定義成組件,然后將小的組件通過組合或者嵌套的方式構(gòu)成大的組件, 最終完成整體UI的構(gòu)建。例如,F(xiàn)acebook的instagram.com整站都采用了React來(lái)開發(fā),整個(gè)頁(yè)面就是一個(gè)大的組件,其中包含了嵌套 的大量其它組件,大家有興趣可以看下它背后的代碼。
- 如果說MVC的思想讓你做到視圖-數(shù)據(jù)-控制器的分離,那么組件化的思考方式則是帶來(lái)了UI功能模塊之間的分離。我們通過一個(gè)典型的Blog評(píng)論界面來(lái)看MVC和組件化開發(fā)思路的區(qū)別
- 對(duì)于MVC開發(fā)模式來(lái)說,開發(fā)者將三者定義成不同的類,實(shí)現(xiàn)了表現(xiàn),數(shù)據(jù),控制的分離。開發(fā)者更多的是從技術(shù)的角度來(lái)對(duì)UI進(jìn)行拆分,實(shí)現(xiàn)松耦合。
對(duì)于React而言,則完全是一個(gè)新的思路,開發(fā)者從功能的角度出發(fā),將UI分成不同的組件,每個(gè)組件都獨(dú)立封裝。
在React中,你按照界面模塊自然劃分的方式來(lái)組織和編寫你的代碼,對(duì)于評(píng)論界面而言,整個(gè)UI是一個(gè)通過小組件構(gòu)成的大組件,每個(gè)組件只關(guān)心自己部分的邏輯,彼此獨(dú)立。


- 組件化開發(fā)特性
React認(rèn)為一個(gè)組件應(yīng)該具有如下特征:
- 可組合(Composeable):一個(gè)組件易于和其它組件一起使用,或者嵌套在另一個(gè)組件內(nèi)部。如果一個(gè)組件內(nèi)部創(chuàng)建了另一個(gè)組件,那么說父組件擁有(own)它創(chuàng)建的子組件,通過這個(gè)特性,一個(gè)復(fù)雜的UI可以拆分成多個(gè)簡(jiǎn)單的UI組件;
- 可重用(Reusable):每個(gè)組件都是具有獨(dú)立功能的,它可以被使用在多個(gè)UI場(chǎng)景;
- 可維護(hù)(Maintainable):每個(gè)小的組件僅僅包含自身的邏輯,更容易被理解和維護(hù);
- 可測(cè)試(Testable):因?yàn)槊總€(gè)組件都是獨(dú)立的,那么對(duì)于各個(gè)組件分別測(cè)試顯然要比對(duì)于整個(gè)UI進(jìn)行測(cè)試容易的多。
- 組件定義
在React中定義一個(gè)組件也是相當(dāng)?shù)娜菀?,組件就是一個(gè) 實(shí)現(xiàn)預(yù)定義接口的JavaScript類:
- 組件渲染
ReactDOM.render 是 React 的最基本方法,用于將模板轉(zhuǎn)為 HTML 語(yǔ)言,并插入指定的 DOM 節(jié)點(diǎn)。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
而這個(gè)方法, 必須而且只能返回一個(gè)有效的React元素。這意味著,如果你的組件是由多個(gè)元素構(gòu)成的,那么你必須在外邊包一個(gè)頂層 元素,然后返回這個(gè)頂層元素。比如我們創(chuàng)建一個(gè)布局組件:
render:function(){
return React.createElement(
"div",null,
React.createElement("div",null,"header"),
React.createElement("div",null,"content"),
React.createElement("div",null,"footer")
);
}
- ES5方式定義組件
"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" }), mountNode);
- Jsx中定義組件
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
ReactDOM.render(<HelloMessage name="John" />, mountNode);
- ES6中定義組件
import './Hello.css';
import './Hello.scss';
import React, {Component} from 'react';
// 內(nèi)聯(lián)樣式
let style={
backgroundColor:'blue'
}
export default class Hello extends Component {
constructor(props) {
super(props);
this.state = { count: 'es6'};
}
render() {
return (
<div>
<h1 style={style}>Hello world{this.state.count}</h1>
<br/>
<image/>
</div>
)
}
}
5 注意事項(xiàng)
(1)你的React組件名稱的首字母應(yīng)當(dāng)大寫,關(guān)于大小寫的差異你會(huì)在后面發(fā)現(xiàn)。
(2)你應(yīng)該會(huì)注意到div元素的樣式類是用 className而不是class聲明的,這是因?yàn)閏lass 是JavaScript的保留字,渲染后,真實(shí)的DOM還會(huì)是:
<div class="ez-led">Hello, React!</div>
Jsx語(yǔ)法
- 什么是jsx
在用React寫組件的時(shí)候,通常會(huì)用到JSX語(yǔ)法,粗看上去,像是在Javascript代碼里直接寫起了XML標(biāo)簽,實(shí)質(zhì)上這只是一個(gè)語(yǔ)法糖,每一個(gè) XML標(biāo)簽都會(huì)被JSX轉(zhuǎn)換工具轉(zhuǎn)換成純Javascript代碼,當(dāng)然你想直接使用純Javascript代碼寫也是可以的,只是利用JSX,組件的結(jié) 構(gòu)和組件之間的關(guān)系看上去更加清晰
- Jsx語(yǔ)法使用
HTML 語(yǔ)言直接寫在 JavaScript 語(yǔ)言之中,不加任何引號(hào),這就是 JSX 的語(yǔ)法,它允許 HTML 與 JavaScript 的混寫。
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
上面代碼體現(xiàn)了 JSX 的基本語(yǔ)法規(guī)則:遇到 HTML 標(biāo)簽(以 < 開頭),就用 HTML 規(guī)則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規(guī)則解析。
JSX 允許直接在模板插入 JavaScript 變量。如果這個(gè)變量是一個(gè)數(shù)組,則會(huì)展開這個(gè)數(shù)組的所有成員
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
上面代碼的arr變量是一個(gè)數(shù)組,結(jié)果 JSX 會(huì)把它的所有成員,添加到模板,運(yùn)行結(jié)果如下。

Data Flow(單向數(shù)據(jù)流)
- 傳統(tǒng)的mvc

到了 Flux 當(dāng)中, 除了名字改變了, 重要的是大量的 Model 歸到了 Store, View 也統(tǒng)一了,從而得到了所謂單向的數(shù)據(jù)流, 就是 Model 和 View 之間關(guān)系非常清晰了。這樣需要人為管理的狀態(tài)就一下少了很多, 結(jié)果體現(xiàn)在開發(fā)應(yīng)用的效率當(dāng)中:
- Flux
- 詳細(xì)學(xué)習(xí)地址:https://hulufei.gitbooks.io/react-tutorial/content/flux.html
- React 標(biāo)榜自己是 MVC 里面 V 的部分,那么 Flux 就相當(dāng)于添加 M 和 C 的部分,F(xiàn)lux 是 Facebook 使用的一套前端應(yīng)用的架構(gòu)模式。
- 一個(gè) Flux 應(yīng)用主要包含四個(gè)部分:
1. dispatcher 處理動(dòng)作分發(fā),維護(hù) Store 之間的依賴關(guān)系
2. stores 數(shù)據(jù)和邏輯部分
3. views React 組件,這一層可以看作 controller-views,作為視圖同時(shí)響應(yīng)用戶交互
4. actions 提供給 dispatcher 傳遞數(shù)據(jù)給 store - 單向數(shù)據(jù)流
先來(lái)了解一下 Flux 的核心“單向數(shù)據(jù)流“怎么運(yùn)作的:
Action -> Dispatcher -> Store -> View
更多時(shí)候 View 會(huì)通過用戶交互觸發(fā) Action,所以一個(gè)簡(jiǎn)單完整的數(shù)據(jù)流類似這樣:

整個(gè)流程如下:
- 首先要有 action,通過定義一些 action creator 方法根據(jù)需要?jiǎng)?chuàng)建 Action 提供給 dispatcher
- View 層通過用戶交互(比如 onClick)會(huì)觸發(fā) Action
- Dispatcher 會(huì)分發(fā)觸發(fā)的 Action 給所有注冊(cè)的 Store 的回調(diào)函數(shù)
- Store 回調(diào)函數(shù)根據(jù)接收的 Action 更新自身數(shù)據(jù)之后會(huì)觸發(fā)一個(gè) change 事件通知 View 數(shù)據(jù)更改了
- View 會(huì)監(jiān)聽這個(gè) change 事件,拿到對(duì)應(yīng)的新數(shù)據(jù)并調(diào)用 setState 更新組件 UI
所有的狀態(tài)都由 Store 來(lái)維護(hù),通過 Action 傳遞數(shù)據(jù),構(gòu)成了如上所述的單向數(shù)據(jù)流循環(huán),所以應(yīng)用中的各部分分工就相當(dāng)明確,高度解耦了。
這種單向數(shù)據(jù)流使得整個(gè)系統(tǒng)都是透明可預(yù)測(cè)的。
Redux
Redux官方中文文檔:http://camsong.github.io/redux-in-chinese/index.html
Reflux:https://segmentfault.com/a/1190000002793786?utm_source=tuicool