React那些事

背景

React是=起源于 Facebook 的內(nèi)部項(xiàng)目浇衬,因?yàn)樵摴緦κ袌錾纤?JavaScript MVC 都不滿意,就決定自己寫一套餐济,用來架設(shè) Instagram 的網(wǎng)站耘擂,2013年5月開源

WHAT

官網(wǎng)是這樣解釋的 —— A JavaScript library for building user interfaces,三大特性如下:

  • Declarative
    聲明式編程絮姆,告訴機(jī)器你想要什么(What)醉冤,讓機(jī)器想出如何做(How)秩霍,
    對應(yīng)的是命令式編程,命令機(jī)器如何去做某件事(How)蚁阳,而不管你要的是什么铃绒,它都會按照你的命令實(shí)現(xiàn)。
  • Component-Based
    任何一個(gè)功能獨(dú)立的模塊都定義成組件螺捐,一個(gè)個(gè)組件通過不斷復(fù)用颠悬,組合與嵌套,構(gòu)成一套完整的UI界面定血。
  • Learn Once, Write Anywhere

核心思想

組件化思想

React 讓我們重新規(guī)劃界面赔癌,把任何一個(gè)功能獨(dú)立的模塊都定義成組件,即被獨(dú)立封裝的可復(fù)用 UI 部件澜沟。一個(gè)個(gè)的組件通過不斷復(fù)用灾票,組合與嵌套等,構(gòu)成一套完整的 UI 界面茫虽。

一個(gè)組件的寫法

import React, { Component } from 'react';
import { render } from 'react-dom';

class HelloMessage extends Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}
render(<HelloMessage name="world" />, mountNode);

render會把這個(gè)組件顯示到頁面上的某個(gè)元素mountNode里面刊苍,顯示的內(nèi)容就是<div>Hello world</div>

組件的劃分

  • 把 UI 劃分出組件層級,可以想想什么情況下我們需要新建一個(gè)函數(shù)或?qū)ο?/strong>)

    • 單一功能原則濒析, DRY
    • 一個(gè)組件應(yīng)該只做一件事情班缰。如果這個(gè)組件功能不斷豐富,它應(yīng)該被分成更小的組件

JSX語法——有些人喜歡它悼枢,而其他人認(rèn)為這是一個(gè)很大的退步,

不得不說是一種非常聰明的做法脾拆,JSX代替?zhèn)鹘y(tǒng)的HTML Templates馒索,讓前端實(shí)現(xiàn)真正意義上的組件化成為了可能

HTML直接嵌入了JS代碼里面,前端被“表現(xiàn)和邏輯層分離”這種思想“洗腦”太久了名船,可能不好接受的設(shè)定之一绰上。

實(shí)際上組件的HTML是組成一個(gè)組件不可分割的一部分,能夠?qū)TML封裝起來才是組件的完全體渠驼,React發(fā)明了JSX讓JS支持嵌入HTML蜈块,但它具有無可爭議的優(yōu)點(diǎn):靜態(tài)分析,JSX標(biāo)記中發(fā)生錯(cuò)誤迷扇,編譯器會立即報(bào)錯(cuò)而不是留待運(yùn)行時(shí)出現(xiàn)莫名其妙的問題百揭。這有助于開發(fā)人員快速排查錯(cuò)誤以及避免其它愚蠢的錯(cuò)誤,比如拼寫錯(cuò)誤蜓席。

好處是你可以不一定使用這種語法器一,但是要使用包含JSX 的組件,是需要“編譯”輸出JS 代碼才能使用的

Virtual DOM

DOM是什么厨内?

DOM是Document Object Model祈秕,就是將XML(或者HTML)內(nèi)的節(jié)點(diǎn)定義成基本統(tǒng)一的對象數(shù)據(jù)可以供程序語言(如javaScript)控制的技術(shù)規(guī)范
通過 DOM 你可以改變網(wǎng)頁渺贤。

你可以使用 Javascript 語言來操作 DOM 以改變網(wǎng)頁。

為了改變網(wǎng)頁请毛,你必須告訴 Javascript 改變哪一個(gè)節(jié)點(diǎn)志鞍。這就是操作 DOM。

真正的 DOM 元素非常龐大方仿,這是因?yàn)闃?biāo)準(zhǔn)就是這么設(shè)計(jì)的固棚。而且操作它們的時(shí)候你要小心翼翼,輕微的觸碰可能就會導(dǎo)致頁面重排玻孟,這可是殺死性能的罪魁禍?zhǔn)住?/p>

React 最大的特色是當(dāng)View層在渲染的時(shí)候,它不會直接從模板里面去構(gòu)建一個(gè)DOM節(jié)點(diǎn). 首先, 它創(chuàng)建一些暫時(shí)的, 虛擬的 DOM, 然后和真實(shí)的DOM還有創(chuàng)建的Diffs一起做對比, 然后才決定需不需要渲染。

當(dāng)組件狀態(tài)state有更改的時(shí)候鳍征,React會自動調(diào)用組件的render方法重新渲染整個(gè)組件的UI黍翎,所以React實(shí)現(xiàn)了一個(gè)Virtual DOM,組件DOM結(jié)構(gòu)就是映射到這個(gè)Virtual DOM上艳丛,React在這個(gè)Virtual DOM上實(shí)現(xiàn)了一個(gè)diff算法匣掸,當(dāng)要重新渲染組件的時(shí)候,會通過diff尋找到要變更的DOM節(jié)點(diǎn)氮双,再把這個(gè)修改更新到瀏覽器實(shí)際的DOM節(jié)點(diǎn)上碰酝,所以實(shí)際上不是真的渲染整個(gè)DOM樹。這個(gè)Virtual DOM是一個(gè)純粹的JS數(shù)據(jù)結(jié)構(gòu)戴差,所以性能會比原生DOM快很多送爸。

Virtual DOM 本質(zhì)上就是在 JS 和 DOM 之間做了一個(gè)緩存∨停可以類比 CPU 和硬盤袭厂,既然硬盤這么慢,我們就在它們之間加個(gè)緩存:既然 DOM 這么慢球匕,我們就在它們 JS 和 DOM 之間加個(gè)緩存纹磺。CPU(JS)只操作內(nèi)存(Virtual DOM),最后的時(shí)候再把變更寫入硬盤(DOM)

Virtual DOM 算法:

  • 觸發(fā)相應(yīng)組件render方法

  • 重新構(gòu)建新的虛擬DOM樹

  • 將當(dāng)前新的虛擬DOM樹和上一次的舊樹進(jìn)行對比

  • 得到DOM結(jié)構(gòu)的區(qū)別亮曹,計(jì)算出最小變化集橄杨,進(jìn)行實(shí)際的瀏覽器DOM更新(批量更新)。

Data Flow

數(shù)據(jù)如何存放照卦,如何更改數(shù)據(jù)式矫,如何通知數(shù)據(jù)更改等等,單向響應(yīng)的數(shù)據(jù)流役耕,從而減少了重復(fù)代碼衷佃,這也是它為什么比傳統(tǒng)數(shù)據(jù)綁定更簡單。

接受輸入數(shù)據(jù)(通過 this.props )蹄葱,組件還可以保持內(nèi)部狀態(tài)數(shù)據(jù)(通過 this.state )當(dāng)一個(gè)組件的狀態(tài)數(shù)據(jù)的變化氏义。

React 組件之間交流的方式

組件免不了要與用戶互動锄列,React 的一大創(chuàng)新,就是將組件看成是一個(gè)狀態(tài)機(jī)惯悠,一開始有一個(gè)初始狀態(tài)邻邮,然后用戶互動,導(dǎo)致狀態(tài)變化克婶,從而觸發(fā)重新渲染 UI筒严。

  • 【父組件】向【子組件】傳值;
    父組件的數(shù)據(jù)可以通過設(shè)置子組件的props傳遞數(shù)據(jù)給子組件
  • 【子組件】向【父組件】傳值情萤;
    可以在父組件中傳一個(gè)callback(回調(diào)函數(shù))給子組件鸭蛙,子組件內(nèi)調(diào)用這個(gè)callback即可改變父組件的數(shù)據(jù)
  • 兄弟組件之間傳值
    沒有任何嵌套關(guān)系的組件之間傳值(PS:比如:兄弟組件之間傳值)
    當(dāng)兩個(gè)組件不是父子關(guān)系,但有相同的父組件時(shí)筋岛,將這兩個(gè)組件稱為兄弟組件娶视。兄弟組件不能直接相互傳送數(shù)據(jù),此時(shí)可以將數(shù)據(jù)掛載在父組件中睁宰,由兩個(gè)組件共享:如果組件需要數(shù)據(jù)渲染肪获,則由父組件通過props傳遞給該組件;如果組件需要改變數(shù)據(jù)柒傻,則父組件傳遞一個(gè)改變數(shù)據(jù)的回調(diào)函數(shù)給該組件孝赫,并在對應(yīng)事件中調(diào)用。

寫了個(gè)簡單的例子如下:

//孫子红符,將下拉選項(xiàng)的值傳給爺爺
var Grandson = React.createClass({
    render: function(){
        return (
            <div>性別:
                <select onChange={this.props.handleSelect}>
                    <option value="男">男</option>
                    <option value="女">女</option>
                </select>
            </div>
        )
    }
});
//子青柄,將用戶輸入的姓名傳給爹  
//對于孫子的處理函數(shù),父只需用props傳下去即可
var Child = React.createClass({
    render: function(){
        return (
            <div>
                姓名:<input onChange={this.props.handleVal}/>
                <Grandson handleSelect={this.props.handleSelect}/>
            </div>
        )
    }
});
//父組件预侯,準(zhǔn)備了兩個(gè)state刹前,username和sex用來接收子孫傳過來的值,對應(yīng)兩個(gè)函數(shù)handleVal和handleSelect
var Parent = React.createClass({
    getInitialState: function(){
        return {
            username: '',
            sex: ''
        }
    },
    handleVal: function(event){
        this.setState({username: event.target.value});
    },
    handleSelect: function(event) {
        this.setState({sex: event.target.value});
    },
    render: function(){
        return (
            <div>
                <div>用戶姓名:{this.state.username}</div>
                <div>用戶性別:{this.state.sex}</div>
                <Child handleVal={this.handleVal.bind(this)} handleSelect={this.handleSelect.bind(this)}/>
            </div>
        )
    }
});
React.render(
  <Parent />,
  document.getElementById('test')
);
  • Props 傳遞數(shù)據(jù)

如果組件嵌套層次太深雌桑,那么從外到內(nèi)組件的交流成本就變得很高,通過 props 傳遞值的優(yōu)勢就不那么明顯了祖今。所以個(gè)人建議盡可能的減少組件的層次校坑,就像寫 HTML 一樣,簡單清晰的結(jié)構(gòu)更惹人愛)

  • 難的地方
    在創(chuàng)建應(yīng)用的每一個(gè) state之前要做的:
  • 確定每一個(gè)需要這個(gè) state 來渲染的組件千诬。
  • 找到一個(gè)公共所有者組件(一個(gè)在層級上高于所有其他需要這個(gè) state 的組件的組件)
  • 這個(gè)公共所有者組件或另一個(gè)層級更高的組件應(yīng)該擁有這個(gè) state耍目。
  • 如果你沒有找到可以擁有這個(gè) state 的組件,創(chuàng)建一個(gè)僅用來保存狀態(tài)的組件并把它加入比這個(gè)公共所有者組件層級更高的地方
  • 當(dāng)應(yīng)用足夠復(fù)雜時(shí)才能體會到它的好處徐绑,雖然在一般應(yīng)用場景下你可能不會意識到它的存在

兄弟組件的溝通的解決方案就是找到兩個(gè)組件共同的父組件邪驮,一層一層的調(diào)用上一層的回調(diào),再一層一層地傳遞props傲茄。如果組件樹嵌套太深毅访,就會出現(xiàn)如下慘不忍睹的組件親戚調(diào)用圖

  • 全局事件
    Context 使用上下文可以讓子組件直接訪問祖先的數(shù)據(jù)或函數(shù)沮榜,無需從祖先組件一層層地傳遞數(shù)據(jù)到子組件中

第三方的類庫

React讓我們有很大的自由度去挑選第三方的類庫,比如

Redux

Redux是一種組織代碼的推薦思想喻粹,就像 “引導(dǎo)數(shù)據(jù)流流向的導(dǎo)流管”蟆融,解決上面那幅關(guān)系復(fù)雜的親戚圖問題

  • 整個(gè)應(yīng)用只有唯一一個(gè)可信數(shù)據(jù)源,也就是只有一個(gè)Store守呜,如 Redux 限定一個(gè)應(yīng)用中只能有單一的 store型酥,這樣的限定能夠讓應(yīng)用中數(shù)據(jù)結(jié)果集中化,提高可控性

  • Action查乒、Reducer弥喉、及 Store

  • State 只能通過觸發(fā)Action 來更改

  • State 的更改必須寫成純函數(shù),也就是每次更改總是返回一個(gè)新的State玛迄,在*Redux 里這種函數(shù)稱為Reducer

Redux 對于組件間的解耦提供了很大的便利由境,如果你在考慮該不該使用 Redux 的時(shí)候,社區(qū)里有一句話說憔晒,“當(dāng)你不知道該不該使用 Redux 的時(shí)候藻肄,那就是不需要的”

Redux 用起來一時(shí)爽,重構(gòu)或者將項(xiàng)目留給后人的時(shí)候拒担,就是個(gè)大坑嘹屯,Redux 中的 dispatch 和 subscribe 方法遍布代碼的每一個(gè)角落。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末从撼,一起剝皮案震驚了整個(gè)濱河市州弟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌低零,老刑警劉巖婆翔,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掏婶,居然都是意外死亡啃奴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門雄妥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來最蕾,“玉大人,你說我怎么就攤上這事老厌∥猎颍” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵枝秤,是天一觀的道長醋拧。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么丹壕? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任庆械,我火速辦了婚禮,結(jié)果婚禮上雀费,老公的妹妹穿的比我還像新娘干奢。我一直安慰自己,他們只是感情好盏袄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布忿峻。 她就那樣靜靜地躺著恤磷,像睡著了一般佩憾。 火紅的嫁衣襯著肌膚如雪医窿。 梳的紋絲不亂的頭發(fā)上佃扼,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天菜秦,我揣著相機(jī)與錄音连锯,去河邊找鬼撮竿。 笑死泉手,一個(gè)胖子當(dāng)著我的面吹牛铣口,可吹牛的內(nèi)容都是我干的滤钱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼脑题,長吁一口氣:“原來是場噩夢啊……” “哼件缸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叔遂,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤他炊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后已艰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊末,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年哩掺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凿叠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嚼吞,死狀恐怖盒件,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情誊薄,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布锰茉,位于F島的核電站呢蔫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜片吊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一绽昏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俏脊,春花似錦全谤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漫萄,卻和暖如春卷员,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腾务。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工毕骡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人岩瘦。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓未巫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親启昧。 傳聞我的和親對象是個(gè)殘疾皇子叙凡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容