如何評價 React Native?(轉自知乎)
不過,盡管都是用JavaScript,但是用React做iOS開發跟做網頁開發是完全兩種體驗。在React Native里你見不到<div>,但是會經常用到<View>,也就是說我們已經完全脫離了HTML的框框,而是用標記語言的格式寫類似XML風格的JS代碼,調用的都是iOS平臺下的原生組件。App在運行時也不會去跑一個WebView,而是只運行一個JavaScript Core VM,然后用Objective-C搭建一個Bridge把iOS的各種組件Expose給JS代碼。React Native實現了一些常用的組件的Bridge可以直接在JS中使用,如果開發者需要使用其他的組件可以自己寫一個Bridge將API Expose給JS VM,所以理論上Native App能做的事情React Native都能做到。
React Native將Flexbox排版移植到了iOS上,也就是說開發者可以不再忍受Constraint-based的Layout Engine,而轉而使用更直觀、更像CSS的Boxed Layout。
JS VM跟iOS的渲染是處于兩個線程的,也就是說JS代碼控制邏輯和Viewer,iOS Framework對Viewer進行渲染。從效率上來看由于JS跟O-C處在兩個線程,不會出現因使用VM而帶來的卡頓,相反App的使用體驗十分流暢。對此不太確信的可以嘗試一下Facebook Groups,你會感覺跟用Native App的體驗沒有什么區別。在開發的過程中JS可以脫離VM來跑,并通過JSON等的序列化來進行通訊,在React Con上的演示就是這樣,他們可以直接用Chrome Developer Tools對App的JS代碼進行調試。
可以看出我先前對React Native的預測基本都說中了,它實現了去WebView化,用iOS原生組件作為Viewer的Render Engine,JS代碼雖然沒有編譯過但是執行效率還不錯。從開發體驗上來看,React Native提供了一套非常完整的開發Workflow,基本上你只要一直跑著iOS Simulator,更新代碼后在Simulator中Cmd-R一下就能刷新App,基本不需要進行編譯。我在想,這樣一來其實一定程度上還能做到App內部的自主更新不是嗎?只要把最新的JS代碼拉下來就能放到VM里面跑了。就是不知道App Store會不會允許這樣的更新機制。
App的Test也可以完全用JS來寫,而且理論上來說Test的Context與Render環境無關,可以脫離iOS直接在本地的Node.js上跑,這對于程序的調試來說也是一種便利。開發者可以在非Mac系統下進行Test-driven的開發而不需要去考慮iOS的具體環境。
當然,從文檔的各種留白我們可以看出React Native現在還處于非常初期的摸索階段,還有很多iOS Framework下的東西沒有很好地整合進去。但是FB已經向我們Proved the Concept,并且消除了人們對效率和兼容性的擔憂。我覺得在現今的基礎上做更深一步的融合是相當迅速的,我相信在接下來的幾個月中我們將看到新一波的Paradigm Shift出現在移動App開發領域。
看到 @rank 把react-canvas都扔出來了我不得不來嘮兩句了。我也是這個星期才在HN上看到的這個項目,實際上這個項目一周前才發布出來。不得不說這的確是一個很贊的實現,我也見過一些用canvas寫的網頁,對移動端的適應做得非常好,比如這個Legend就設計得很酷炫。
但是,從我目前了解到的信息來看,react-canvas在制作規模化移動端應用方面并不能趕超React Native的勢頭,原因如下:
相比之下,React Native致力于去掉更多的中間層,只保留一個Flux+React的中心概念,這才是一個合理的發展趨勢。我見到有人說React Native跟react-canvas兩者不沖突,可以用canvas做React Native的渲染引擎。說這話的人還是沒有認識到React Native的目的究竟在哪。我說了React Native在于去掉中間層,你又要用回canvas再加上一個WebView和一堆JavaScript,那React Native的意義何在?就好比喬布斯千方百計把iPhone的厚度減少了一毫米,你帶個套又給人加回去了一樣。
看了所有的答案,都沒有講清楚React的實質作用在哪。
我上周用純React完成了一個CMS發布系統的界面框架,數據層僅僅用了Parse的JS庫,但是功能還算完備。中間讀了不少這方面的資料,對Flux + React有了一個較為系統的了解。這里大致總結一下給還沒開始動手寫React的人一點啟發。
要講React的實質作用那一定不能脫離Flux模型。一說到Flux,很多人的第一反應就是那個經常見到的、看起來很復雜的Loop流程圖。我不想一開始就貼那張圖,因為我默認你們都沒真正用過React,那張圖只能讓你們更加不明覺厲。其實了解Flux + React最好的方法就是看看官網給的這個視頻,我就把重點摘出來講講吧。
首先,Flux是為了解決MVC模型中數據流向不一致的問題的。視頻中給出了一個非常典型的案例,可以說我以前也被類似的問題折騰了好久。比方說你從服務端拉下來的數據要改變兩個View的內容,比如給未讀消息的數字提醒+1,然后把消息放到Chat View中,如果用戶正在看當前的Chat View就把未讀消息數字-1。這一連串的操作在沒有用React的時候要怎么寫?她給出的代碼也是我以前處理類似狀況的方法:
我以前也不是沒想過寫一個MessageManager之類的,類似Flux的Dispatcher一樣的東西去控制這些邏輯然后分別對不同的View進行改動,但是好好想想這不過是一個簡單的信息接收而已啊,為啥要復雜到專門給一個數字寫一個Dispatcher去做這種事情?所以最后想想還是算了,代碼丑點就丑點,能用就行,最后我也寫成上面那樣了。但是你要知道,這樣的代碼寫在異步程序里是非常危險的!如果用戶同時在操作,那你的代碼很可能就會被中斷報錯的。還有,如果后期需要加功能,比如在屏幕側邊再搞個信息框,那你怎么知道在哪去加代碼?你程序的數據交換會像這樣混亂:
怎么樣?寫異步MVC的童鞋有沒有感同身受?臉書以前的Chat就是經常因為異步數據的問題被人黑。比如經常是右上角一個紅色的1,點進去一看啥都沒有,強迫癥的怒火你可曉得?
那么問題來了:如何讓異步數據像同步數據一樣正確地顯示出來?臉書的攻城獅想到一個絕妙的招式:咱別一個DOM一個DOM的去更新內容了,來一次數據俺們就“刷新”頁面!是的,就是回到了90年代的那種模式:你想看新郵件?請刷新頁面!然后服務端把你當前的郵件全部讀一遍,排好序,生成好HTML,然后給你寄過來,你就能看到新郵件啦。Flux就是這么干的,只不過現在已經是21世紀了,渲染HTML這種工作不需要服務端也能做,我們也不用真的去刷新整個網頁,雖說Chat的那個問題的確可以靠刷新頁面解決掉lol。Flux的(大致)做法是:來新的數據了,好,我把它Merge到客戶端的舊數據中,然后把客戶端存著的所有數據交給一個Render,然后把整個HTML從頭到尾渲染一邊,最后把新的HTML替換掉現有的HTML就好啦!那么之前那個Chat的代碼咱就可以這樣寫(我YY的,視頻沒有,也不是React代碼)
function newMassageHandler(newMessage) {
this.messages.push(newMessage);
this.renderTheWholePage(); // In practice it should be an Action Creator
}
看到沒有?管你有多少個View,你們自個兒去算怎么渲染吧,handler只管存數據跟提醒渲染。如果哪個View計算完了說,不對,那個Unread Message Number要-1,好,你跟Action Creator說一聲,他會在下一輪渲染前把這個項目加到數據中的。如此一來就不會出現把改動View的代碼寫到某個Controller中,然后一個Controller又要同時關聯好幾個View的情況,這樣一來整個程序的結構就變得非常清晰了。這時候再看這張圖就容易理解多了:
數據的流向變得非常統一,如果View要對數據做些改動也得等整個View渲染完了在下一輪渲染的時候再改,從而形成一個非常完整的Loop,這對異步數據的處理是非常有幫助的。 Flux是一個取代MVC的設計模式,而React就是臉書寫的給Flux用的專門做Viewer的框架。由于Flux要將原有的HTML從頭到尾渲染一邊,那么就不得不考慮一個平滑過渡的問題,因為畢竟我們要講究用戶體驗,不能每次收到數據就真的把原網頁給刪了然后重新給用戶畫一個,那用戶還不崩潰啊?React解決這個問題的辦法就是用Virtual DOM,這才是React真正的核心價值。其原理是寫看起來像是DOM的JS代碼,然后生成ReactDOMElement的對象,而不是真正的DOM,然后把新的Virtual DOM Tree跟用戶正在看的DOM Tree做個Diff,然后用最小的改動量Update整個網頁。對比一下jQuery大概就是這樣:
// jQuery
$('<button>').text('Submit').on('click', submitHandler);
// <button>Submit</button>
// React without JSX
React.creatElement('button', {onClick: submitHandler}, 'Submit');
// <ReactDOMButton>Submit</ReactDOMButton>
// React with JSX
<button onClick={submitHandler}>Submit</button>
可以看到,其實JSX只是React的一個語法糖,這只不過是一門DSL。有些人一看到JSX就說把HTML寫JS里了,我真是不知道該怎么評價這種人。ReactDOMButton并不是真的DOM,在運行時只是一個普通的JS Object,我寫成XML形式只是易讀。不用真的DOM當然是因為效率問題,這也是一種優化手段,但是Virtual DOM的好處當然不止這樣,后面會講。 你要是不喜歡JavaScript也沒事,我就不喜歡。知道GitHub的Atom嗎?就是用CoffeeScript + React寫的。它并不是用改過語法的那個看起來就很惡心的coffee-react項目,而是自己寫了一個很簡單的helper來做簡單的Transform。大致的原理是這樣的:
{div, button} = require('react').DOM
div
className: 'message'
onClick: @messageHandler
'some messages'
button()
我覺得這樣的寫法真的很簡潔很優雅,而且一想到這寫的根本就不是HTML也沒碰一行JavaScript就覺得很開心啊。不過我是LiveScript黨,有更加簡潔的語法,把Atom的helper改了改現在用在別的項目中用得很方便。
看到這樣的寫法觀眾就應該很清楚地明白了React的原理了吧,它實際上就是把DOM元素全部變成了JS的類,可以直接用JS等價的代碼調用new出來。(實際上是要用一個factory包著才能用的,0.12后把createFactory整合到createElement里面了所以現在用法上更加簡潔)
但是千萬不要以為React就只是JS世界中的東西,其實它也是受到別的領域的啟發呢。上面那個視頻中后半段詳細介紹了React,其實React這種idea受啟發于游戲的渲染。有很多游戲都是數據來了,跟現在的數據Merge一下,然后update數據結構,diff一下老的結構,然后再部分渲染。所以說React其實最重要的還是一種使用Virtual Element描述界面的方式,而因為這種方式容易進行二次計算,所以能夠保證最小幅度的影響用戶體驗,最大幅度地保證數據跟界面的一致。因此React才能夠很輕易地使用在后端,做給Spider渲染HTML的工作。要知道Angular在之前是做不到這一點的,對搜索引擎的優化竟然要用到PhantomJS!而且這種方式竟然還演變成了收費的服務!簡直讓人咋舌。但是React卻能做到,因為它并不受限于JavaScript,臉書最先用React做后端的時候是PHP的,后來整合Instagram的時候才分離出來寫了開源的JS庫。
所以我覺得React Native的最終形式并不僅僅是把Web做到移動端上,因為那樣根本沒法跟Native的比。而是要把React這種Viewer的架構在Native上實現,把原有的模板式UI重構成Virtual Elements,然后以更加動態的方式渲染。不過就目前的開發進度來看,這個目標還是遙遙無期。
不深思則不能造于道。不深思而得者,其得易失。
名人名言- 曾國藩
- By 知乎
- 2015-10-16
- 2567
- 公司新聞,網站開發,網站設計,UI