为什么说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
總結
以上是生活随笔為你收集整理的为什么说ReasonReact是编写React的最佳方式?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MyBatis拦截器原理探究MyBati
- 下一篇: 为什么在EOS上的DApp对开发人员来说