網誌

React use() 與 Suspense:無瀑布的資料串流

儀表板上的六張卡片,六個旋轉器,它們不會一起出現——它們一個接一個出現,像骨牌一樣,因為每張卡片只在上面的完成後才開始載入。這就是瀑布,總等待時間不是最慢的請求,而是所有請求的總和。use() 和 Suspense 斷開了這個鏈條——但有趣的是其中的機制:暫停的元件實際上拋出了什麼,以及錯誤順序到達的 HTML 如何最終落在正確的位置。

Core Web Vitals:INP 究竟量度甚麼,以及 scheduler.yield() 如何拯救主執行緒

在關於微互動的文章中,我提過 transform 和 opacity 是在合成器執行緒上做動畫,所以即使頁面很重,按鈕動畫理論上也不應該卡頓。這句話依然成立——但有一個那篇文章沒有提到的但書:如果主執行緒被一個長時間的 JS 工作阻塞,動畫可能根本沒有機會開始執行,因為連點擊事件的處理函式本身都還在排隊等候。INP 正是量度這個落差的指標——而 scheduler.yield() 是少數能真正把這個落差補上的方法之一。

content-visibility:免虛擬化清單的畫面外渲染

一千則留言的清單渲染得很慢,於是你搬出 react-window——換來流暢的捲動,卻犧牲了 Ctrl+F、列印頁面,以及部分螢幕閱讀器導覽,因為視窗外的元素在 DOM 中已經不復存在。content-visibility 用另一種方式解決同一個問題:元素仍然留在 DOM 裡,瀏覽器只是暫時跳過為它們計算版面配置與繪製的昂貴工作,直到它們接近可視範圍為止——而且令人意外的是,當你在其中搜尋文字時,它還能暫時把它們顯露出來。

Popover API 與原生 <dialog>:告別從零手寫的 modal

在無障礙設計那篇文章裡,一個用 display:none 隱藏、卻依然存在於可訪問性樹裡的 modal,正是從零開始用 div 手寫 modal 會出現的典型錯誤。真正該問的問題是:一開始為甚麼要從零開始做?本文探討原生 <dialog> 和 popover 屬性能免費送你甚麼——top layer、焦點陷阱、light dismiss——以及這兩個機制之間的分別大到甚麼程度,混用它們是通往不可訪問介面最簡單的一條路。

React 的 Optimistic UI:故意說謊的介面

「讚好」按鈕立即作出反應,心心圖示填滿,數字隨即增加——而伺服器根本還沒有回應。這不只是微互動那篇文章講過的速度錯覺,而是更進一步的事情:介面展示了一個尚未存在的狀態,並且假定它馬上就會成真。本文探討如何安全地實作這種模式——包括假設落空時要如何老實地收回這個謊言,以及為甚麼手寫 setState 加 catch,是 useOptimistic 提供的方案的劣質版本。

Next.js 的 Server Actions:JavaScript 尚未加載,表單已經在運作

「use server」看起來就像是呼叫 API route 的 fetch 的語法糖——正因如此,大部分實作都把它當成普通的函式呼叫來對待。這是一個會帶來具體後果的誤解:每一個標記為「use server」的函式,都會變成網絡上一個公開的端點,而建基於這個機制的表單,甚至在 JavaScript 尚未加載完成之前就已經可以運作。本文探討這個指令背後實際發生的事情,以及那些單看文件未必一眼就能看出的陷阱。