React Native 分析(一)基本原理概述

React 的理念
React 的主要思想是通過構建可復用組件來構建用戶界面。所謂組件,其實就是有限狀態(tài)機(FSM)鄙早,通過狀態(tài)渲染對應的界面,且每個組件都有自己的生命周期椅亚,它規(guī)定了組件的狀態(tài)和方法需要在哪個階段改變和執(zhí)行限番。
簡單的來說,如下圖:


image.png

比較裝逼的來說呀舔,有限狀態(tài)機弥虐,表示有限個狀態(tài)以及在這些狀態(tài)之間的轉移和動作等行為的模型。一般通過狀態(tài)、事件霜瘪、轉換和動作來描述有限狀態(tài)機珠插。下圖 是描述組合鎖狀態(tài)機的模型圖,包括 5 個狀態(tài)粥庄、5 個狀態(tài)自轉換丧失、6 個狀態(tài)間轉換和 1 個復位 RESET 轉換到狀態(tài) s1。狀態(tài)機能夠記住目前所處的狀態(tài)惜互,可以根據(jù)當前的狀態(tài)做出相應的決策布讹,并且可以在進入不同的狀態(tài)時做不同的操作。狀態(tài)機將復雜的關系簡單化训堆,利用這種自然而直觀的方式可以讓代碼更容易理解描验。

image.png

React 正是利用這一概念,通過管理狀態(tài)來實現(xiàn)對組件的管理坑鱼。例如膘流,某個組件有顯示和隱藏兩個狀態(tài),通常會設計兩個方法 show() 和 hide() 來實現(xiàn)切換鲁沥,而 React 只需要設置狀態(tài) setState({ showed: true/false }) 即可實現(xiàn)呼股。同時,React 還引入了組件的生命周期這個概念画恰。通過它彭谁,就可以實現(xiàn)組件的狀態(tài)機控制,從而達到“生命周期→狀態(tài)→組件”的和諧畫面允扇。

雖然組件缠局、狀態(tài)機、生命周期這三者都不是 React 獨創(chuàng)的考润,但 Web Components 標準與其中的自定義組件的生命周期的概念相似狭园。就目前而言,React 是將這幾種概念結合得相對清晰糊治、流暢的 View 實現(xiàn)唱矛。

UI = ?(count) =
 div(
 span('Count ' + count),
 button('Add +1')
 ) 

在 React 中,數(shù)據(jù)是自頂向下單向流動的井辜,即從父組件到子組件绎谦。這條原則讓組件之間的關系變得簡單且可預測。
state 與 props 是 React 組件中最重要的概念抑胎。如果頂層組件初始化 props燥滑,那么 React 會向下遍歷整棵組件樹,重新嘗試渲染所有相關的子組件阿逃。而 state 只關心每個組件自己內部的狀態(tài)铭拧,這些狀態(tài)只能在組件內改變赃蛛。把組件看成一個函數(shù),那么它接受了 props 作為參數(shù)搀菩,內部由 state 作為函數(shù)的內部參數(shù)呕臂,返回一個 Virtual DOM 的實現(xiàn)。

在使用 React 之前肪跋,常見的 MVC 框架也非常容易實現(xiàn)交互界面的狀態(tài)管理歧蒋,比如 Backbone。它們將 View 中與界面交互的狀態(tài)解耦州既,一般將狀態(tài)放在 Model 中管理谜洽。但在 React 沒有結合 Flux 或 Redux 框架前,它自身也同樣可以管理組件的內部狀態(tài)吴叶。在 React 中阐虚,把這類狀態(tài)統(tǒng)一稱為 state。

當組件內部使用庫內置的 setState 方法時蚌卤,最大的表現(xiàn)行為就是該組件會嘗試重新渲染实束。這很好理解,因為我們改變了內部狀態(tài)逊彭,組件需要更新了咸灿。

render(){   
    return (
        <div>
            <span>
                Count:<b>{this.state.count}</b>
            </span>
            <button onClick={() => ???}>
                Add +1
            </button>
        </div>
    )
}

所以??? 就是 this.setState({count:this.state.count + 1})

數(shù)據(jù)更新過程
因為View的展示和View的事件響應分屬于不同的端,展示部分的描述在JS端侮叮,響應事件的監(jiān)聽和描述都在Native端避矢,通過Native轉發(fā)給JS端。Native開發(fā)里签赃,什么時候會執(zhí)行代碼谷异?只在有事件觸發(fā)的時候分尸,這個事件可以是啟動事件锦聊,觸摸事件,timer事件箩绍,系統(tǒng)事件孔庭,回調事件。而在React Native里材蛛,這些事件發(fā)生時OC都會調用JS相應的模塊方法去處理圆到,處理完這些事件后再執(zhí)行JS想讓OC執(zhí)行的方法,而沒有事件發(fā)生的時候卑吭,是不會執(zhí)行任何代碼的芽淡,這跟Native開發(fā)里事件響應機制是一致的。 會在下一節(jié)具體說明

就拿一個簡單的點擊按鈕豆赏,更新 text 計數(shù)來說挣菲,點擊以后富稻, Native會分發(fā)如下事件:

[_bridge enqueueJSCall:@"EventEmitter.receiveTouches" args:@[
  @"end",
  @{@"x": @42, @"y": @106}]];

經(jīng)過 bridge轉換后,就變成

call('EventEmitter', 'receiveTouches', [{x: 42, y: 106}])

如果組件自身的 state 更新了白胀,那么會依次執(zhí)行 shouldComponentUpdate椭赋、componentWillUpdate、render 和 componentDidUpdate或杠。

class App extends Component {
  componentWillReceiveProps(nextProps) {
    // this.setState({})
  }

  shouldComponentUpdate(nextProps, nextState) {
    // return true;
  }

  componentWillUpdate(nextProps, nextState) {
    // ...
  }

  componentDidUpdate(prevProps, prevState) {
    // ...
  }
}

shouldComponentUpdate 是一個特別的方法哪怔,它接收需要更新的 props 和 state,讓開發(fā)者增加必要的條件判斷向抢,讓其在需要時更新认境,不需要時不更新。因此挟鸠,當方法返回 false 的時候元暴,組件不再向下執(zhí)行生命周期方法。
shouldComponentUpdate 的本質是用來進行正確的組件渲染兄猩。怎么理解呢茉盏?我們需要先從初始化組件的過程開始說起,假設有如圖所示的組件關系枢冤,它呈三級的樹狀結構鸠姨,其中空心圓表示已經(jīng)渲染的節(jié)點。

image.png

當父節(jié)點 props 改變的時候淹真,在理想情況下讶迁,只需渲染在一條鏈路上有相關 props 改變的節(jié)點即可

image.png

而默認情況下,React 會渲染所有的節(jié)點核蘸,因為 shouldComponentUpdate 默認返回 true巍糯。正確的組件渲染從另一個意義上說,也是性能優(yōu)化的手段之一客扎。

回到 RN 來說祟峦,RN框架會根據(jù)傳遞進來的信息,計算出應該哪個節(jié)點響應事件徙鱼,并把該組件的 ID 作為參數(shù)傳入宅楞。如果shouldComponentUpdate返回 true需要渲染,則讓 Native 進行更新渲染袱吆。

var UIManager = require('NativeModules').UIManager;
UIManager.update(18, {text: '43'});

通過MessageQueue發(fā)送相應的數(shù)據(jù)給 Native 處理

NativeModules.UIManager = {
    ...
    update: function(viewID, attributes) {
        MessageQueue.push(
            ['UIManager', 'update', [viewID, attributes]]
        );
    }
    ...
};

轉換成的 Native 代碼厌衙,markAsDirty標記此控件需要更新,等待 VSync 事件更新

[UIManager updateView:18 props:@{@"text": @"43"}]
 addUIBlock:^() {
   UILabel *label = viewRegistry[18];
   label.text = @"43";
   [label markAsDirty];
}

簡要的流程圖

image.png

說了這么多绞绒,其實最重要的概念婶希,還是

UI = ?(data)

image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蓬衡,隨后出現(xiàn)的幾起案子喻杈,更是在濱河造成了極大的恐慌拐揭,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奕塑,死亡現(xiàn)場離奇詭異堂污,居然都是意外死亡,警方通過查閱死者的電腦和手機龄砰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門盟猖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人换棚,你說我怎么就攤上這事式镐。” “怎么了固蚤?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵娘汞,是天一觀的道長。 經(jīng)常有香客問我夕玩,道長你弦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任燎孟,我火速辦了婚禮禽作,結果婚禮上,老公的妹妹穿的比我還像新娘揩页。我一直安慰自己旷偿,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布爆侣。 她就那樣靜靜地躺著萍程,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兔仰。 梳的紋絲不亂的頭發(fā)上茫负,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音斋陪,去河邊找鬼朽褪。 笑死置吓,一個胖子當著我的面吹牛无虚,可吹牛的內容都是我干的。 我是一名探鬼主播衍锚,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼友题,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了戴质?” 一聲冷哼從身側響起度宦,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤踢匣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后戈抄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體离唬,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年划鸽,在試婚紗的時候發(fā)現(xiàn)自己被綠了输莺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡裸诽,死狀恐怖嫂用,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情丈冬,我是刑警寧澤嘱函,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站埂蕊,受9級特大地震影響往弓,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蓄氧,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一亮航、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匀们,春花似錦缴淋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至祖灰,卻和暖如春钟沛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背局扶。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工恨统, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人三妈。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓畜埋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親畴蒲。 傳聞我的和親對象是個殘疾皇子悠鞍,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內容