[譯] 為什麼說 ReasonReact 是編寫 React 的最佳方式?
作者|David Kopal
譯者|無明
使用 React 開發使用者介面是一件很酷的事情,但我們能讓它變得更酷、更好嗎?要讓它變得更好,我們首先需要找出它存在的問題。那麼,React 作為 JavaScript 庫還存在哪些問題?
React 最初並不是為 JavaScript 而開發
如果你仔細看一下 React,你會發現,它的一些主要原則與 JavaScript 有點格格不入。讓我們來談談不變性、函數語言程式設計原則,特別是型別系統。
不可變性是 React 的核心原則之一。你不想改變 prop 或 state,因為如果這樣做了,可能會遇到不可預測的後果。但 JavaScript 並沒有提供開箱即用的不可變性。我們通過約定的方式來保持資料結構的不可變性,或者我們使用 immutableJS 之類的庫來實現不可變性。
React 採用了函數語言程式設計的原則,因為 React 應用程式實際上是函式的組合。儘管 JavaScript 提供了一些這方面的特性(如一等函式),但它仍然不是一門函數語言程式設計語言。當我們想編寫宣告性程式碼時,需要使用外部庫,如 Lodash/fp 或 Ramda。
那麼,型別系統有什麼問題呢?在 React 中,我們有 PropTypes。我們用它們來模仿 JavaScript 的型別,因為它本身不是靜態型別語言。為了利用高階靜態型別,我們需要使用外部依賴庫,例如 Flow 和 TypeScript。
React 和 JavaScript 的比較
如你所見,JavaScript 與 React 的核心原則不相容。
有沒有另一門程式語言與 React 具有更好的相容性?
或許 ReasonML 就是這樣的一門語言。
Reason 提供了開箱即用的不可變性。因為它是基於函數語言程式設計語言 OCaml,所以也具備了 OCaml 內建的一些特性。Reason 還提供了一個強大的型別系統。
React、JavaScript 和 Reason 比較
Reason 與 React 的核心原則相容。
Reason
Reason 並不是一門新語言,它是 OCaml 的另一種 JavaScript 風格的語法和工具鏈,而 OCaml 是一門已經存在了 20 多年的函數語言程式設計語言。Reason 是由 Facebook 的開發人員建立的,他們已經在一些專案中使用了 OCaml(如 Flow、Infer)。
Reason 具有 C 語言風格的語法,這讓來自 JavaScript 或 Java 等主流語言的人很容易上手。相比 OCaml,Reason 提供了更好的文件和不斷增長的社群。此外,它還可以與現有的 JavaScript 程式碼庫整合。
OCaml 是 Reason 背後的語言。Reason 與 OCaml 具有相同的語義——只是語法不同。這意味著你可以使用 Reason 的 JavaScript 風格的語法來編寫 OCaml 程式碼。因此,你可以利用 OCaml 的強大特性,例如強大的型別系統和模式匹配。
我們來看一下 Reason 的語法示例。
let fizzbuzz = (i) => switch (i mod 3, i mod 5) { | (0, 0) => "FizzBuzz" | (0, _) => "Fizz" | (_, 0) => "Buzz" | _ => string_of_int(i) }; for (i in 1 to 100) { Js.log(fizzbuzz(i)) };
我們在這個例子中使用了模式匹配,但它仍然與 JavaScript 非常像,對吧?
不過,瀏覽器目前唯一可用的語言仍然是 JavaScript,所以我們需要將它編譯成 JavaScript。
BuckleScript
BuckleScript 編譯器是 Reason 的一個強大特性,它可以將 Reason 程式碼編譯成可讀且高效能的 JavaScript,並移除死程式碼。如果你所在團隊中不是每個人都熟悉 Reason,就讓他們閱讀編譯好的 JavaScript 程式碼。
Reason 與 JavaScript 非常相似,以至於編譯器都不需要對某些 Reason 程式碼做任何修改。因此,你可以享受靜態型別語言帶來的好處,而無需修改任何程式碼。
let add = (a, b) => a + b; add(6, 9);
這段程式碼在 Reason 和 JavaScript 中都是有效的。
BuckleScript 附帶了四個庫:標準庫 Belt(OCaml 的標準庫不夠強大),以及與 JavaScript、Node.js 和 DOM API 的繫結。
由於 BuckleScript 是基於 OCaml 編譯器,所以編譯速度比 Babel 要快得多,也比 TypeScript 快上幾倍。
現在讓我們編譯我們在 Reason 中編寫的 FizzBuzz 演算法程式碼。
通過 BuckleScript 將 Reason 程式碼編譯成 JavaScript 程式碼
如你所見,生成的 JavaScript 程式碼可讀性很高,看起來就像是由 JavaScript 開發人員編寫的。
Reason 不僅可以被編譯為 JavaScript,還可以被編譯為原生代碼和位元組碼。因此,你可以使用 Reason 開發一個應用程式,然後在 macOS、Android 和 iOS 手機上的瀏覽器上執行。Jared Forsyth 開發了一款叫做 Gravitron(https://github.com/jaredly/gravitron)的遊戲,它就是用Reason 開發的,它可以在我剛剛提到的所有平臺上執行。
與 JavaScript 的互操作性
BuckleScript 還為我們提供了與 JavaScript 的互操作性。你不僅可以將 JavaScript 程式碼貼上到 Reason 程式碼庫中,還可以讓 Reason 程式碼與 JavaScript 程式碼打交道。這意味著你可以輕鬆地將 Reason 程式碼整合到現有的 JavaScript 程式碼庫中。此外,你可以在 Reason 程式碼中使用 NPM 生態系統中的所有 JavaScript 包。例如,你可以在一個專案中組合使用 Flow、TypeScript 和 Reason。
當然,事情並沒有看上去的那麼簡單。要在 Reason 中使用 JavaScript 庫或程式碼,首先需要通過 Reason 繫結將它們移植到 Reason。換句話說,需要對無型別的 JavaScript 程式碼賦予型別,然後才能能夠利用 Reason 的強型別系統。
如果要在 Reason 中使用 JavaScript 庫,可以通過瀏覽 Reason Package Index(Redex)資料庫看看這個庫是否已被移植到 Reason。Redex 是一個網站,它聚合了使用 Reason 和 JavaScript 庫編寫的庫和工具。如果在那裡找到了你需要的庫,就可以將其作為依賴項安裝,並在 Reason 應用程式中使用它。
如果沒有找到你需要的庫,就需要自己編寫 Reason 繫結。如果你是個 Reason 新手,那麼要注意,編寫 Reason 繫結是一件很有挑戰性的事情。
如果你只需要 JavaScript 庫中的某些功能,就不需要為整個庫編寫 Reason 繫結,而是對需要使用的功能或元件編寫繫結即可。
ReasonReact
這篇文章是關於如何使用 Reason 開發 React 程式碼,這要歸功於 ReasonReact 庫。
或許你還在想:“我仍然不知道為什麼要使用 Reason 來開發 React”。
正如之前提到的那樣,主要原因是 Reason 與 React 的相容性比 JavaScript 更好。因為 React 是為 Reason 而生的,或者更準確地說是為 OCaml 而生的。
ReasonReact 之路
React 的第一個原型是由 Facebook 使用 Standard Meta Language(StandardML,OCaml 的表兄弟)開發的,然後被遷移到 OCaml,React 也隨之被轉錄為 JavaScript。
這是因為整個 Web 都在使用 JavaScript,說出“我們將在 OCaml 中構建 UI”這樣的話是不明智的。它確實奏效了——使用了 JavaScript 的 React 已被廣泛採用。
然後,我們習慣了認為 React 就是 JavaScript 庫。React 與其他庫和語言一起(Elm、Redux、Recompose、Ramda 和 PureScript),讓函數語言程式設計在 JavaScript 中流行起來。隨著 Flow 和 TypeScript 的興起,靜態型別也變得流行起來。因此,具有靜態型別的函數語言程式設計正規化成為前端世界的主流。
2016 年,Bloomberg 開發並開源了 BuckleScript,這是一種將 OCaml 轉換為 JavaScript 的編譯器。他們因此能夠使用 OCaml 的強型別系統來開發安全的前端程式碼。
函數語言程式設計的普及以及 BuckleScript 的釋出為 Facebook 提供了理想的環境,讓他們萌生了回到最初使用 ML 語言開發 React 的想法。
他們採用 OCaml 的語義和 JavaScript 的語法建立了 Reason。他們還建立了 React 的 Reason 包裝器——ReasonReact,提供了額外的特性,例如在有狀態元件中封裝 Redux 原則。這樣一來,他們讓 React 迴歸到了初心。
React 和 Reason 的威力
當 React 進入 JavaScript 世界時,因為 React 存在的不足,我們需要引入各種庫和工具來。這也意味著專案對其他庫的依賴性很高。有些依賴庫還處在開發階段,而且還會定期引入重大變更。因此,我們不得不在專案中謹慎維護這些依賴項。
這為 JavaScript 開發增加了另一層複雜性。
典型的 React 應用程式至少具有以下依賴項:
-
靜態型別——Flow/TypeScript
-
不可變性——immutableJS
-
路由——ReactRouter
-
格式——Prettier
-
lint——ESLint
-
輔助功能——Ramda/Lodash
現在讓我們切換到 ReasonReact。
我們還需要這些依賴嗎?
-
靜態型別——內建
-
不可變性——內建
-
路由——內建
-
格式——內建
-
ling——內建
-
輔助函式——內建
在 ReasonReact 應用程式中,你不需要這些依賴項,因為語言本身提供了很多關鍵特性。維護軟體包將變得更加容易,並且不會隨著時間的推移而增加複雜性。
這一切要歸功於已有 20 多年曆史的 OCaml。它是一門成熟的語言,所有核心原則都很穩定。
總 結
起初,Reason 的建立者面臨兩種選擇。採用 JavaScript 在一定程度上會讓它變得更好,但同時也會背上一些歷史負擔。
最終,他們走的是一條不一樣的路。他們採用了 OCaml,一門成熟的語言,具有出色的效能,並對其進行了修改,讓它看起來很像 JavaScript。
React 也遵循了 OCaml 的原則,這就是為什麼在 Reason 中使用 React 會獲得更好的開發者體驗。React 和 Reason 是構建 React 元件的一種更安全的方式,因為有強型別系統的支援,你不需要處理大多數在 JavaScript 中存在的問題。
下一步
如果你是來自 JavaScript 世界,就可以輕鬆地上手 Reason,因為它的語法與 JavaScript 很像。如果你一直在使用 React,那麼接下來會更輕鬆,之前所有的 React 知識都可以繼續派上用場,因為 ReasonReact 具有與 React 相同的模型和非常相似的工作流程。這意味著你無需從頭開始,在開發過程中邊用邊學 Reason。
在專案中開始使用 Reason 最好的做法是循序漸進地進行。你可以將 Reason 程式碼用在 JavaScript 中,反之亦然。對於 ReasonReact 也是一樣的。你可以將 ReasonReact 元件用在 React JavaScript 應用程式中,反之亦然。這種增量方法已被 Facebook 開發人員所採用,他們在開發 Facebook Messenger 時就大量使用了 Reason。
相關連結
ReasonML: https://reasonml.github.io/
ReasonReact: https://reasonml.github.io/reason-react/
OCaml: https://ocaml.org/
BuckleScript: https://bucklescript.github.io/
Belt: https://bucklescript.github.io/bucklescript/api/Belt.html
英文原文:
https://medium.freecodecamp.org/psst-heres-why-reasonreact-is-the-best-way-to-write-react-5088d434d035
活動推薦
前端發展至今,社群中出現了很多高質量的框架與解決方案,在有限的研發資源下,團隊需要儘可能多地使用社群的方案解決問題。12 月 7-8 日在北京國際會議中心舉辦的 ArchSummit 全球架構師技術峰會邀請了超過百位的國內外專業講師,並設定了前端技術專題,分享他們的最新黑科技和研發經驗。
目前大會 8 折優惠購票火熱進行中, 掃描以下圖片二維碼 或點選“ 閱讀原文 ”瞭解更多詳情!
如有疑問歡迎諮詢票務經理灰灰:17326843116(微信同號)