天天看點

Solid.js 就是我理想中的 React

作者 | Nick Scialli

譯者 | 王強

策劃 | 闫園園

我大約在三年前開始在工作中使用 React。巧合的是,當時正好是 React Hooks 出來的時候。我當時的項目代碼庫有很多類元件,總讓我覺得很笨重。

我們來看看下面的例子:一個每秒遞增一次的計數器。

對于一個自動遞增的計數器來說要寫這麼多代碼可不算少。更多的模闆和儀式意味着出錯的可能性更大,開發體驗也更差。

Hooks 很漂亮,但是容易出錯

當 hooks 出現的時候我非常興奮。我的計數器可以簡化為以下寫法:

等等,這其實是不對的。我們的 useEffect hook 在 count 周圍有一個陳舊閉包,因為我們沒有把 count 包含在 useEffect 依賴數組中。從依賴數組中省略變量是 React hooks 的一個常見錯誤,如果你忘記了,有一些 linting 規則會警告你的。

我稍後會回到這個問題上。現在,我們把缺少的 count 變量添加到依賴數組中:

但現在我們遇到了另一個問題,看看應用程式的運作效果:

精通 React 的人們可能知道發生了什麼事情,因為你每天都在與這種問題作鬥争:我們建立了太多的間隔(每次重新運作效果時都會建立一個新間隔,也就是每次我們增加 count 時間隔都會增加)。可以通過幾種方式來解決這個問題:

從清除間隔的 useEffect hook 傳回一個清理函數

使用 setTimeout 代替 setInterval(還是要使用清理函數)

使用 setCount 的函數形式來避免直接引用目前值

事實上哪種辦法都行得通。我們在這裡實作最後一個選項:

我們的計數器修好了!由于依賴數組中沒有任何内容,是以我們隻建立了一個間隔。由于我們為計數設定器使用了回調函數,是以永遠不會在 count 變量上有陳舊閉包。

這是一個人為做出來的例子,但除非你已經使用 React 一段時間,否則它仍然很令人困惑。我們中有許多人每天都會遇到更複雜的情況,即使是最有經驗的 React 開發人員也會為之頭痛不已。

假的響應性

我思考了很多關于 hooks 的事情,想知道為什麼它們感覺不太對勁。結果我通過探索 Solid.js 找到了答案。

React hooks 的問題在于 React 并不是真正的響應式設計。如果 linter 知道一個效果(或回調或 memo)hook 何時缺少依賴項,那麼為什麼架構不能自動檢測依賴項并對這些更改做出響應呢?

深入研究 Solid.js

關于 Solid,首先要注意的是它沒有嘗試重新發明輪子:它看起來很像 React,因為 React 有一些顯眼的模式:單向、自上而下的狀态;JSX;元件驅動的架構。

如果我們用 Solid 重寫 Counter 元件,會這樣開始:

到目前為止我們看到了一個很大的不同點:count 是一個函數。這稱為通路器(accessor),它是 Solid 工作機制的重要組成部分。當然,我們這裡沒有關于按間隔遞增 count 的内容,是以下面把它添加進去:

這肯定行不通,對吧?每次元件渲染時不會設定新的間隔嗎?

沒有。它就這麼正常運作了。

但為什麼會這樣?好吧,事實證明 Solid 不需要重新運作 Counter 函數來重渲染新的計數。事實上,它根本不需要重新運作 Counter 函數。如果我們在 Counter 函數中添加一個 console.log 語句,就會看到它隻運作一次。

在我們的控制台中,隻有一個孤獨的日志語句:

"The Counter function was called!"在 Solid 中,除非我們明确要求,否則代碼不會多次運作。

但是 hooks 呢?

于是我在 Solid 中解決了 React useEffect hook 的問題,而無需編寫看起來像 hooks 的東西。我們可以擴充我們的計數器例子來探索 Solid 效果。

如果我們想在每次計數增加時 console.log count 怎麼辦?你的第一反應可能是在我們的函數中使用 console.log:

但這不起作用。請記住,Counter 函數隻運作一次!但我們可以使用 Solid 的 createEffect 函數來獲得想要的效果:

這行得通!而且我們甚至不必告訴 Solid,說這個效果取決于 count 變量。這才是真正的響應式設計。如果在 createEffect 函數内部調用了第二個通路器,它也會讓效果運作起來。

一些更有趣的 Solid 概念

響應性,而不是生命周期 hooks

如果你已經在 React 領域有一段時間的經驗了,那麼下面的代碼更改可能真的會讓你大跌眼鏡:

并且代碼仍然是有效的。我們的 count 信号不需要存在于一個元件函數中,依賴它的效果也不需要。一切都隻是響應式系統的一部分,“生命周期 hooks”實際上并沒有起到太大的作用。

細粒度的 DOM 更新

前面我主要關注的是 Solid 的開發體驗(例如更容易編寫沒有錯誤的代碼),但 Solid 的性能表現也得到了很多贊譽。其強大性能的一個關鍵來源是它直接與 DOM 互動(無虛拟 DOM)并執行“細粒度”的 DOM 更新。

考慮對我們的計數器進行以下調整:

運作它會在控制台中獲得以下日志:

換句話說,每秒更新的唯一内容是包含 count 的一小部分 DOM。Solid 甚至沒有重新運作同一 div 中較早的 console.log。

小 結

在過去的幾年裡我很喜歡使用 React;在處理實際的 DOM 時,我總感覺它有着正确的抽象級别。話雖如此,我也開始注意到 React hooks 代碼經常變得容易出錯。我感覺 Solid.js 使用了 React 的許多符合人體工程學的部分,同時最大程度減少了混亂和錯誤。本文向你展示的是 Solid 的一些讓我驚歎的部分,感興趣的話我建議你檢視https://www.solidjs.com并自己探索這個架構。

https://typeofnan.dev/solid-js-feels-like-what-i-always-wanted-react-to-be/

繼續閱讀