【與React.js 核心開發(fā)者的一次談話記錄】
譯者注:本譯文是在「在線對話 React.js 核心開發(fā)者」一個半小時直播的基礎(chǔ)上進行的原文翻譯,包括了直播中的所有問答內(nèi)容,盡可能保留了 Dan 回答的中心語義,部分表達為了語句通順、方便理解,適當(dāng)使用了成語或短語替代。文章超過 1.5w 字,文中包含了大量的專業(yè)概念與啟發(fā)性思想,通讀大約需要 30 分鐘。建議先收藏下來,慢慢閱讀。最后祝大家都能夠有所收獲!

主持人:Hi Dan,來跟觀看直播的小伙伴們打個招呼吧!
Dan:嗨,大家好!
主持人:現(xiàn)場大多數(shù)人都已經(jīng)認(rèn)識你了,可不可以再介紹你一下你自己?
Dan:謝邀,我是 Dan,是 React 的核心維護者之一,過去 5 年一直在 React Team 工作。這差不多就是我的自我介紹了。
12 歲開始編程
主持人:我從你的博客中看到,你從 12 歲就開始編程了,非常的厲害,你是怎樣對編程產(chǎn)生興趣的呢?
Dan:應(yīng)該說是機緣巧合吧,我其實并不是自己主動去學(xué)習(xí)編程的。當(dāng)時在學(xué)校做作業(yè)的時候,我很喜歡做一些展示。我不知道大家現(xiàn)在還用不用 PPT ,當(dāng)時我用的是 PowerPoint 2003,PPT 中內(nèi)置了一種編程語言。如果你點擊右鍵打開菜單,可以完成一些宏錄制的操作。這些操作會產(chǎn)生很多小的程序,我起初不知道它們是什么,但是我非常的感興趣,之后我就買了一些書,從此開始了編程的學(xué)習(xí)。
React 狀態(tài)管理工具
主持人:這是你第一次和中國的工程師見面,我們這邊準(zhǔn)備了很多問題,你準(zhǔn)備好回答熱心網(wǎng)友們的提問了嗎?
Dan:我準(zhǔn)備好了。
主持人:你對 React 狀態(tài)管理工具怎么看的?
Dan:我想不同的人可能會選用不同的庫,如果要我來做推薦的話,我可能不會去推薦任何一個特定的庫。真正重要的問題不是選擇什么狀態(tài)管理庫,而是理解「狀態(tài)」的類型,理解「狀態(tài)」是什么。因為「狀態(tài)」是一個比較籠統(tǒng)的、比較大的概念,我認(rèn)為我們不應(yīng)該去浮于表面地去討論哪個庫更好,而是去看你要處理的狀態(tài)是什么種類,使用這些庫的目的是什么,選用不同方案帶來的差異是什么。比如說,有一些 UI 狀態(tài),針對的是顯示的 UI 組件。針對文本輸入框來說,文本內(nèi)容有哪些,文本是否被選中,是否處于 focus / hover 狀態(tài),或者是記錄當(dāng)前頁面被選中的 Tab 之類的,這些都是 UI 的狀態(tài)。另一種狀態(tài)更像是 cache,緩存從服務(wù)器返回的數(shù)據(jù),它可能更像是某種草稿。所以我們需要結(jié)合實際的需求去選擇狀態(tài)管理工具。對于 UI 狀態(tài)來說,我個人不推薦使用任何庫,使用 React 自帶的狀態(tài)就夠了??梢允褂?React State 或者是 React Context,通過組件樹將狀態(tài)傳遞下去。對于數(shù)據(jù)緩存的場景來說,我并不推薦使用 “狀態(tài)管理” (此處 Dan 用手比了個引號 ????)相關(guān)的解決方案。我更建議你使用一些專門用來處理數(shù)據(jù)緩存的庫,比如 React Query,Apollo 和 React Relay。
主持人:現(xiàn)在很多人都想用 React Hooks 和 Context 去代替 Redux,你剛才的回答也提到了類似的點,你可不可以分享一些 React Hooks 背后的設(shè)計理念?
Dan:現(xiàn)在 React Hooks 只能被用于函數(shù)組件,我們也沒有計劃讓它們兼容 class 組件,因為這是兩種不同的范式,把它們混淆在一起并不合理。
我認(rèn)為,這更像是一個關(guān)于 Hooks 設(shè)計理念的問題,我不確定應(yīng)該怎么回答??偟膩碚f,Hooks 某種程度上反映了我們是如何看待 React Component 的。從概念上講,Component 就是一個函數(shù),它接收一些 props 屬性,然后返回 UI。Hooks 是對這個函數(shù)的一個增強,組件樹上有了狀態(tài)的一席之地,你可以用 Hooks 去記錄狀態(tài),或是去記錄行為等等。這就是一個大致的思路。順著這個思路走下去,React 可能不像一個庫,你可以把他想象成是 UI 的編程語言。在編程語言中,我們有函數(shù)、變量這些概念。如果把 React 看作是一門 “偽” 編程語言的話,Component 就對應(yīng)編程語言中的函數(shù),而 Hooks 就對應(yīng)變量。這是我自己的想法,不知其他同學(xué)能不能 get 到。
快速上手 React
主持人:很多開發(fā)者認(rèn)為 React 的入門非常的難,所以有沒有推薦新手快速上手的方法?
Dan:我認(rèn)為這取決于大家為什么覺得入門很難,大家遇到的問題可能不盡相同。其中一點是,React 需要你有 JavaScript 編程基礎(chǔ)。如果你是第一次接觸編程的話確實會比較困難,因為它不是使用 HTML 和模板進行網(wǎng)站搭建的。對于有些庫和框架,你從模板開始,在模板上添加一些條件判斷或循環(huán),通過不斷的小修小補,你就逐漸學(xué)會了如何進行編程。但在 React 這里,你是從編程語言開始,一上來就要寫代碼。如果你不會編程,React 的學(xué)習(xí)曲線就比較陡峭。有些人剛接觸 React 覺得很難上手,等過一段時間學(xué)會了 JavaScript ,再回來看 React 就不那么困難了,這就是 JavaScript 帶來的門檻。另一方面,我覺得有個好的開發(fā)環(huán)境很重要。比如 Next.js 或是 create-react-app 這類工具會幫你把項目開發(fā)所需的配置都準(zhǔn)備好。有時候,人們覺得入門難只是因為搞不懂如何才能創(chuàng)建一個單頁應(yīng)用(SPA)。這些并不是 React 的問題,但人們往往會將它們歸咎到 React 身上。如果你把 Next.js 作為項目起點的話,我覺得會是一個不錯的開始。
React 避坑
主持人:下一個問題。對于已經(jīng)開始用 React 的人來說,可不可以給一些建議,幫助大家避免一些坑?
Dan:有一點很重要,如果你使用 React Hooks,那么通常都要使用配套的 lint 規(guī)則。我們對 Hooks 有兩個推薦的規(guī)則,可以使用插件的方式集成到你的項目里。此外,我覺得理解 React 中的兩個概念很重要。其一是 不變性(immutability ),你需要知道如何做到更新 (update) 狀態(tài),而不改變(mutate)它。這一點你可以用 擴展操作符(...)或是其他語法實現(xiàn)。這里推薦一個很棒的庫叫 immer,它可以讓你在編程中使用 Vue / Svelte 風(fēng)格的變更操作,但同時又能夠保持不變性。如果你對這點很苦惱的話不妨試一試。另一點是你要理解 React 的渲染流程應(yīng)當(dāng)是純粹的(Rendering is supposed to be pure),當(dāng)組件進行渲染的時候,它就是在計算下一個 UI 應(yīng)該長什么樣子,你不應(yīng)該在渲染流程中摻雜其他的操作。我認(rèn)為理解 UI 是計算結(jié)果 (UI is a calculation)這個范式是非常重要的。
函數(shù)式編程
主持人:目前 React 越來越靠近函數(shù)式編程(functional programming)了,但有人說 JavaScript 并不是一個注重函數(shù)式編程的語言,你如何看待這個矛盾?
Dan:可能 React 確實比其他 UI 庫更偏向函數(shù)式一些,但我不認(rèn)為它是一個面向函數(shù)式編程的框架。人們在這方面其實有個共識,那就是所有喜歡函數(shù)式編程的人都不覺得 React 是函數(shù)式的,因為它不夠“純粹”或是一些其他的原因。對于 React,我更喜歡「functional-lite / functional-light programming」這個概念。React 從函數(shù)式編程中借鑒的一個很重要的思想就是將復(fù)雜的事物分解成幾個可以組合的函數(shù),像是盡可能地去使用不變性(immutability)。但 React 的代碼看上去并不像傳統(tǒng)的函數(shù)式編程代碼,因為 React 傾向于使用更加直接的編碼風(fēng)格。舉個例子,如果你需要一個循環(huán),你可以直接在代碼中寫循環(huán),而不需要寫更高階的函數(shù),然后再用復(fù)雜的方式將他們組合起來。寫 React 的方法就和寫 JavaScript 一樣,所以代碼看上去也不像是 Ramda 或者 Lodash FP 那樣的「函數(shù)式」。所以 React 應(yīng)該算是處于一種中間地帶吧。它既集成了函數(shù)式編程的想法與概念,又能讓你在大多數(shù)的時候使用 JavaScript 主流的編程方式去進行編碼,我覺得這應(yīng)該不算是矛盾吧。
前端發(fā)展太快?
主持人:目前的前端是一個正在飛速發(fā)展的領(lǐng)域,你是如何不斷提高自己,跟隨技術(shù)進步的腳步的呢?
Dan:很有趣的問題,其實我覺得前端的發(fā)展并沒有那么快。我這些年沒有看到太多的新的東西,有可能是我自己看的不夠仔細吧。不過我看到的大多數(shù)成果都是已有功能的迭代與完善。有些東西每一年或者兩年發(fā)布個新的版本,但是大多數(shù)情況下不管是新的發(fā)行版還是新的庫,用的思想還是原來的思想。所以,如果你對已經(jīng)存在的東西足夠熟悉、理解足夠深的話,你可能就不會對新出現(xiàn)的東西感到新奇了,因為它們某種程度上講是同質(zhì)化的東西。所以我覺得準(zhǔn)備迎接新事物的最好方法就是去熟悉已有的東西,當(dāng)你足夠熟悉之后,你看到就只有相似性了。
主持人:React 的未來發(fā)展趨勢是怎樣的?
Dan:這是個大問題啊,像是未來十年的路線圖之類的,我們現(xiàn)在正在做的很多功能其實都與這個問題相關(guān)。
主要問題
主持人:那么目前最主要的 Issue 有哪些呢?
Dan:這一點很有意思,我們其實在面對很多不同的問題,也有不同的 team 在用不同的方式去解決它們。我可以給你舉幾個例子,比如說數(shù)據(jù)獲?。╠ata-fetching)。如何設(shè)計一個具有良好擴展性的數(shù)據(jù)獲取方案,使得組件的數(shù)量不會引起請求 Waterfall,從而保證 UI 的一致性。你可以將邏輯寫在離被調(diào)用位置更近的地方,這樣數(shù)據(jù)和代碼就能實現(xiàn)并行加載。data-fetching 是一個相當(dāng)復(fù)雜的問題,你還要考慮到如何讓用戶用著方便,現(xiàn)在的 data-fetching 其實還是挺惱人的。這是當(dāng)下要解決的一個大問題,另一個大的主題是各種的優(yōu)化,關(guān)于代碼分割(code-splitting),服務(wù)器端渲染(Server Side Rendering),如何將多余的東西從 JavaScript 的打包中剔除出去,如何讓 Hydration 的花銷更小等等。這可能聽上去像是一個完全不同的領(lǐng)域,但是類似的點還有很多,通過這些優(yōu)化我們可以讓 React 從本質(zhì)上優(yōu)于第三方庫和其他解決方案。另一個大的主題是關(guān)于動畫(animation)的,但我們還沒有開始這個方向的相關(guān)工作。但對于上述的所有方向,我們都會嘗試與以往不同的方案去解決。很多 UI 框架或者庫都傾向于去獨立應(yīng)對單點的問題,針對單個問題給出不同的解決方案,通過提供某些便利的 API 實現(xiàn)更優(yōu)的開發(fā)體驗等等。但我們在我們看來,有些問題是彼此關(guān)聯(lián)的。我們會嘗試使用更理論、更系統(tǒng)的方式串聯(lián)起相關(guān)聯(lián)的問題,然后解決它們。所以如果要我講 React 未來的樣子的話,我希望它能夠成為一個工具,一個幫助我寫組件的工具,里面集成了 data-fetching,代碼分割,動畫渲染等等所有功能,而且這些功能都無縫地組合在一起。因為 React 的中心思想就是像樂高一樣,將各部分功能組合起來,我們希望在未來能夠支持這些功能。
Concurrent Mode
主持人:有些朋友們問到了 concurrent mode 的相關(guān)問題。React 的 concurrent mode 自 16 版本就已經(jīng)提出了,但到了 React 18 才終于發(fā)布了出來。React Team 在設(shè)計這個功能的時候遇到了哪些問題和挑戰(zhàn),你們對于這個功能在將來又有哪些計劃呢?
Dan:好的,我首先要說明一下,React 18 還沒有正式發(fā)布,我們目前只為庫的維護者們發(fā)布了一個 alpha 版本。如果你訪問 reactjs.org/blog,你會看到一篇名為《The Plan for React 18》的文章。如果朋友們想去了解 React 18 的新功能或者發(fā)布的時間計劃可以去看一下。我們還建立了一個工作小組,并邀請了 50 名左右的社區(qū)開發(fā)者來協(xié)助我們完成一些 React 18 發(fā)布的相關(guān)工作,比如確保整個 React 生態(tài)中的庫都能兼容新的版本。相關(guān)信息都在 GitHub Discussion 里面,非組員雖然不能評論,但是可以閱讀。你可以從中找到很多關(guān)于發(fā)版的信息,其中就包括你問的 concurrent mode 的信息。正如你所說,我們在很多年前就聲明了要做真正的 concurrent mode,不過這期間有一個很大的策略上的變化,那就是它不再作為一個單獨的模式(mode) 來呈現(xiàn)。所以我們最終添加到 React 中的可能并不是一個 concurrent mode,而是一種并發(fā)渲染的機制。本質(zhì)上來說,并發(fā)意味著 React 有能力在同一時間更新多項狀態(tài)。比如你在更新狀態(tài)的時候,有些獲取數(shù)據(jù)的狀態(tài)更新會花費比較長的時間,渲染一個復(fù)雜頁面的時間成本就會很高。如果使用了并發(fā)渲染,這些場景下 React 就不會阻塞住瀏覽器。這意味著頁面在進行長時間的狀態(tài)更新的同時,你還可以去輸入文字,后臺的狀態(tài)更新不會阻塞你的交互?;旧?,你可以把并發(fā)渲染想象成是在后臺跑 setState()。這確實是我們一直想在 React 中實現(xiàn)的功能,但重要的是它不再是一個單獨的模式了。當(dāng)你需要使用并發(fā)能力的時候,我們提供了一個叫 Transition 的功能,你可以用 Transition 包裹 setState() 的操作,這樣在調(diào)用 API 的時候 React 就會進行并發(fā)渲染。所以這個在將來會是一個可以隨時調(diào)用的特性,而不是作為一個 Web 應(yīng)用的全局的模式,他只針對于你包裹的操作生效。就挑戰(zhàn)而言,我們確實遇到了不少挑戰(zhàn)。因為我們是從理論出發(fā)的,我們得出了很多理論性的想法,比如我們認(rèn)為「并發(fā)是好的」,「長時間阻塞瀏覽器是不合理的」,「渲染應(yīng)該是可以被打斷的」等等。然后我們基于這些想法著手去做,在 2015 年完成了一個原型,之后又重寫了 React 來讓它能夠真正實現(xiàn)這些想法,這就是 React 16 版本。之后我們確實花費了幾年的時間來思考如何能夠?qū)⑦@些功能應(yīng)用到實際生產(chǎn)中。全新的 Facebook 官網(wǎng) facebook.com 就使用了 React 的并發(fā)特性。諸如 「渲染應(yīng)該是可中斷的」,「setState() 應(yīng)該是并發(fā)的」以及「渲染應(yīng)該在后臺完成」這些小小的想法實際上帶來了很多的后果,這也是我們花了一段時間才意識到的。這些特性帶來了更好的服務(wù)器端渲染(server-rendering),更好的代碼分割 (code-splitting) 和更好的數(shù)據(jù)獲?。╠ata-fetching),在將來我們還會用相同的思路去實現(xiàn)更好的動畫效果。這個想法在很多地方都得到了體現(xiàn),因為它本質(zhì)上為 React 提供了讓渲染能夠「異步」的能力,這個世界上有很多東西天生就是異步的,比如我上面提到的那些功能。梳理這些功能,搞清楚怎么讓他們一起運作起來確實花了我們不少時間。但我們現(xiàn)在基本上都已經(jīng)搞定了,這些特性都會集成到 React 18 里面。所以,我再一次建議感興趣的朋友去 React 官網(wǎng)的博客查看 React 18 的發(fā)布計劃,點擊相關(guān)的討論區(qū)查看相關(guān)的細節(jié)。
體驗 React 18 Alpha
主持人:所以聽眾們現(xiàn)在就可以使用 React 18 Alpha 版來體驗相關(guān)功能了對嗎?
Dan:是的,但有兩點需要注意。其一是要去博客看一下新版本的使用說明。比如項目升級了版本之后可能需要將 ReactDom.render() 方法替換成 ReactDom.createRoot() 方法,諸如此類會有一些新的 API 進來,如果你不做替換的話,程序可能會報 warning,但這就是你開始使用新特性的方式。另一點是 strict mode 的用戶們需要注意的,新版的 strict mode 會更加嚴(yán)格,這就意味著原有的東西在新版本下可能會 break 掉。所以如果你的程序在新版 React 中完全跑不起來了,可以嘗試移除 strict mode,可能就是這個原因?qū)е碌?。還有一點需要記住的是,alpha 版 React 主要是為庫的開發(fā)者們提供的版本,有很多庫,比如 Redux 等,本身還沒有更新支持。所以如果你的項目依賴了大量的第三方庫,那你的項目在更新 React 18 后很可能會崩潰,但這就這個發(fā)行版的目的,讓庫的作者有充足的時間去做升級。所以,如果你發(fā)現(xiàn)你的項目在新版 React 中完全運行不了也不要灰心,尤其是那些因為引入第三方庫導(dǎo)致程序崩潰的用戶們,等到 React 穩(wěn)定版發(fā)布的時候,大多數(shù)流行的庫應(yīng)該都已經(jīng)修復(fù)了問題并且做到了兼容。
React Lane
主持人:能簡單介紹下 React Lane 是怎么設(shè)計的嗎?
Dan:這是一個相當(dāng)技術(shù)性的問題。我們其實不希望別人知道有 React Lane 這個東西,因為它不是一個公開的 API,而是一個涉及到 React 內(nèi)部實現(xiàn)的東西。但我可以簡要說明一下它是什么。正如我上面說的,我們?yōu)?React 添加了并發(fā)的功能,這意味著任意時刻都有可能有多個狀態(tài)在同步更新。并發(fā)對于我們的 Transition 特性尤為重要。比如說你在輸入框進行輸入,回車后頁面更新,這是一個常規(guī)的頁面更新操作。但如果你想要在輸入的同時實現(xiàn)自動補全,或者想要從網(wǎng)絡(luò)上獲取候選項列表需要連接后端,從前的做法是你使用 useEffect 自己去管理這些異步渲染的流程。但現(xiàn)在我們會在 React 內(nèi)置這套流程,你可以用同步的代碼寫法來處理異步的數(shù)據(jù)操作。我一直認(rèn)為 UI 是一個瞬間的狀態(tài)(state in time),或者說瞬間的時刻(moment in time),所以要表達這一點,你應(yīng)該為列表的結(jié)果創(chuàng)建一個 Transition,這樣瀏覽器請求可能會花費一些時間,但是等數(shù)據(jù)回來的時候 React 會負(fù)責(zé)正確地去展示結(jié)果。Lanes 是一個 React 內(nèi)部的機制,用來標(biāo)記 React 當(dāng)前正在處理哪項狀態(tài)的更新。你可以想象當(dāng)你每次調(diào)用 setState() 的時候,React 會把他加到一個 bitmask 中,類似于很多的開關(guān)(switch)或者是復(fù)選框(checkbox)。有點像是任務(wù)列表,如果你用過任務(wù)列表你就知道任務(wù)有高優(yōu)先級和低優(yōu)先級?;蛘呤?Github 上的 Label,Label 可以用來標(biāo)記是高優(yōu)先級,也可以用來標(biāo)記 bug,feature,discussion。同樣對于 setState() 來說,React 也提供了一組標(biāo)簽,來標(biāo)記它是不是 Transition,是否是一個緊急更新等等,這個標(biāo)簽就是 Lane。當(dāng) React 進行渲染的時候,它會根據(jù) Lane 來選擇哪些狀態(tài)更新需要被執(zhí)行。如果有一個緊急的狀態(tài)更新,需要一次緊急的頁面重新渲染,這時候就只會執(zhí)行在 Urgent Lane 下的狀態(tài)更新。之后如果所有緊急的更新操作都完成了,我再去檢查 Transition Lane 中的狀態(tài)更新,如果這個時候從網(wǎng)絡(luò)上返回了數(shù)據(jù),那就把它渲染出來,比如去加載自動補全的候選項列表。所以說 Lane 是 React 的一個內(nèi)部機制,使用 bitmask 來將狀態(tài)更新與優(yōu)先級關(guān)聯(lián)起來,之后 React 再根據(jù)它去更新狀態(tài)。
React Server Component
主持人:Server Component 的 RFC 草案去年年底發(fā)布了,請問 Server Component 的主要目的是什么。
Dan:是的,我們?nèi)ツ?12 月發(fā)布了一個 Server Component 的技術(shù)預(yù)覽,但它還處于比較早期的階段。這應(yīng)該算是一個還處在研究階段的特性,與 React 18 相比更偏實驗性,也不會包含在 React 18 的特性之中,可能會在其之后才發(fā)布。但廣義上來說,它與 SSR 并不一樣,這也是人們常?;煜狞c。最大的區(qū)別是,Server Component 只運行在服務(wù)器上,它不會被下載下來。你可以把它們想象成某種 API,以往的客戶端應(yīng)用可能會請求 JSON API 來獲取數(shù)據(jù), Server Component 與之類似,但是 API 換成了在服務(wù)器端運行的組件。這樣做的優(yōu)勢是你不需要去下載任何代碼,可以達成性能上的優(yōu)化。另一個優(yōu)勢是,因為這些組件運行在服務(wù)器端,它們可以直接與數(shù)據(jù)庫、微服務(wù)、或者其他任何在這臺服務(wù)器上的資源進行通信。你不需要把這些資源暴露給客戶端,就把它們留在服務(wù)器上就好。
主持人:有些用戶已經(jīng)嘗試過使用 Server Component 了,所以當(dāng)我們需要在項目中使用服務(wù)器組件的時候,我們需要維護三個組件而不是一個,這帶來了額外的復(fù)雜性不是嗎?
Dan:好的,對于這個問題,我個人其實不太認(rèn)同這種說法。我不想把這個問題定義為我們需要維護三個組件而非一個。我覺得更準(zhǔn)確的說法是,在傳統(tǒng)的 React 中,我們只有一種類型的組件;而在 Server Component 中,我們把它們分成了 Server Component,Client Component 和 Shared Component。這個問題就好比你原本只有一部手機,現(xiàn)在你既有手機、又有手表、又有電視,但這并不意味著你要同時去用這三個東西,你只是有了更多的選擇。所以對于這個問題而言,不是說你的組件在將來都會以三種形態(tài)存在,而是你現(xiàn)在只能用 Client Component 的組件。如果只用 Client Component 能夠滿足需求的話固然很好,但是當(dāng)這個 Server Component 這個特性落地的時候,你會有更多的選擇來做相同的事。到那個時候,如果你想要使用 React 寫博客,想要讀取文件系統(tǒng),這些操作不需要很多復(fù)雜的框架也能做到。如果你只是想要使用 PHP 或者 Rails 類似的傳統(tǒng) web 編程風(fēng)格去做一些數(shù)據(jù)庫的讀取操作,Server Component 也能幫你做到。在大多數(shù)場景下,我們預(yù)期用戶們會通過框架來使用 Server Component 功能,比如使用 Next.js。所以幸運的話,你并不需要想太多,也不需要創(chuàng)建什么 API,你只需要在文件名中加上 .server.js,這個文件就可以在服務(wù)器端運行,你就可以使用所有 Server Component 的功能了。
主持人:所以我們可以直接通過一些框架來使用這個功能?
Dan:是的,我覺得大部分情況應(yīng)該都是如此。因為框架就像是整個項目的基礎(chǔ)設(shè)施一樣,會為你連接并組織好項目的各個部分。雖然你也可以去手動配置,但是肯定不如使用框架來的方便。特別是框架還可以實現(xiàn)無配置的啟用這些功能,如果你要自己動手,你就得自己把項目的各個部分串聯(lián)起來。目前我們還沒有針對如何使用 Server Component 給出使用的建議,但是鑒于 Next.js 已經(jīng)支持了 Server Component,如果你想要部署自己的 Server Component,你可以去看看他們是怎么實現(xiàn)的,然后復(fù)制他們的做法。又或者你可以直接使用 Next.js 或者其他類似的框架。
React 與 Vue
主持人:人們常把 React 與 Vue 作比較。你個人是如何比較這二者的呢?希望能從設(shè)計、性能和使用目的來談一談。
Dan:首先我個人沒有使用過 Vue,所以我可能做不了特別詳細的比較。從技術(shù)上來講,兩者可能采取了不同的實現(xiàn)方式吧。Vue 建立在 mutability 的基礎(chǔ)上,可以直接去修改 state。這樣做帶來了一些好處,它寫起來更簡單,你可以用 mutative style 去寫代碼,這種寫碼方式也受到了許多開發(fā)者的喜愛。但它也有一些缺陷,比如站在更高的層次來看,有些功能可能是出了名的難以實現(xiàn),或者根本不可能實現(xiàn)。比如我們正在做的 Transition 功能,又或者是我們想要做的新的動畫特性。二者之間的差異太大,就像被一道深深的技術(shù)鴻溝隔開了,Vue 在不斷探索我們可以用 mutability 做什么,而 React 在不斷探索 immutability 能夠做到的事。但我們對自己的方向非常有信心,因為我們的背后有近 50 年的函數(shù)式編程的研究成果,所以我們明白雖然在落實到實踐中可能會遇到一些困難,但是從理論分析的角度我們的方法還是合理的。Vue 和 React 只是在探索兩個不同的方向,這件事很好,你只需選擇自己喜歡的那個就好。談到設(shè)計的話,我覺得二者最大的區(qū)別是 Vue 更傾向于去做一些妥協(xié)與折衷,也更關(guān)注能不能去解決實際的問題。比如它會提供一些人們呼聲很高的功能,包括更加便利的動畫,更加便利的條件渲染、組件模板等等。但 React 可能不太一樣,我們希望確保 React 提供的每個解決方案都是完全可靠的、可信賴的。所以對于某些僅為了方便而存在的功能,我們抱著寧缺毋濫的態(tài)度,寧愿不去實現(xiàn)它們。比如 React 想要重做動畫功能,我們最終交付給用戶的功能一定比現(xiàn)有方案快上好幾倍。我們不會去標(biāo)準(zhǔn)化一些現(xiàn)有的方案,因為我們對如何實現(xiàn)動畫這個功能有自己的構(gòu)想,這個構(gòu)想會與 React 庫深入結(jié)合,它會不同于我們現(xiàn)在看到的所有框架。所以說,在 Vue 中,你可以更快地得到自己想要的功能,但是在 React 這里你可能找不到自己想要的功能,只能依賴第三方庫來實現(xiàn),直到我們搞清楚解決問題的方法,知道如何把這個功能做對、做好,我們才會把它集成到 React 中來。這就有點像 Android 和 iOS 在設(shè)計理念上的區(qū)別。iOS 相對 Android 就經(jīng)常會少一些功能,比如最初幾版 iOS 連復(fù)制粘貼的功能都沒有,直到出現(xiàn)了通知中心才有了復(fù)制粘貼功能。iOS 的特性可能確實會滯后一些,但是當(dāng)它確定要做某件事的時候,它會把他實現(xiàn)的非常好,我想這也是我們的工作理念。我認(rèn)為兩種思路各有優(yōu)劣吧。
Flow 與 TypeScript
主持人:Vue 3 已經(jīng)不再使用 Flow 了,而 React 還在使用,對這一點你怎么看?
Dan:我不覺得這一點很重要啊。這更多還是取決于庫本身是如何編寫的,我們目前還是需要去做一些靜態(tài)的類型檢查。不過這與用戶們使用的 React 類型沒有關(guān)系,只影響 React 庫自身的開發(fā)。我們使用 Flow 只是因為我們一開始就用了它,它也能滿足我們后續(xù)的需求。我們也可以使用 Typescript,但我覺得這不是很關(guān)鍵。這完全不會影響到 React 的用戶,因為我們內(nèi)部的類型和我們暴露出去的類型也有差異。所以這件事不是很重要,我們并不 care。我們當(dāng)然可以切到 Typescript,但遷移成本較高,不值得我們這樣做。
React 的競爭力
主持人:最近有些新出現(xiàn)的前端框架,比如 Svelte 和 Solid-js,他們都不再使用 Virtual-DOM 了,并且聲稱在性能表現(xiàn)和 bundle 體積上都超越了 React,你怎么看待這一點?
Dan:還是一樣,我沒有深度地體驗過這些框架,所以我不太好下論斷。但還是那句話,看上去總有新的東西在出現(xiàn),但其實并不是這樣的。真正能夠走通的設(shè)計思路其實并不多,React 在走 immutable 這條路,Vue 和 Svelte 在走 mutable 這條路,然后 Svelte 和 Vue 之間在具體實現(xiàn)上可能會有些差異,Solid-js 應(yīng)該也是這條路上的一個分支。說到 Virtual-DOM,我其實不是很喜歡這個術(shù)語。我們盡量不去使用這個詞,因為每個人對它都有不同的理解。但我覺得它不是一個與性能有關(guān)的東西。我想再重申一遍,我不愿去使用 Virtual-DOM 這個詞,因為它是一個非常容易混淆的概念。當(dāng)我們提到 “Virtual-DOM” 這個詞的時候,我們說的其實是一種 UI 在內(nèi)存中的表現(xiàn)形式。這應(yīng)該是你期望得到的東西,因為它為開發(fā)者提供了更多的選擇。比如 Server Component 是運行在服務(wù)器端的,但是它需要定義一個數(shù)據(jù)格式來傳遞服務(wù)器輸出的結(jié)果,然后在客戶端接收。如果你使用 Server Component 做了一個頁面過渡的效果,你肯定希望將它與現(xiàn)有的 UI 合并起來。但這一點又跟 PHP 或者 Rails 那種傳統(tǒng)的客戶端渲染不一樣,傳統(tǒng)方法渲染的時候,老的頁面會消失,然后新的頁面逐漸加載,它并不保留任何的狀態(tài)。如果你有一個搜索框,你輸入一些東西,點擊搜索跳轉(zhuǎn)到新頁面,此時搜索框會被清空。但使用 Server Component 不會發(fā)生類似的事情,我們把組件樹發(fā)回給客戶端,我們可以在客戶端中將它和現(xiàn)有的 UI 做 diff ,然后渲染有差異的部分,所以搜索框的狀態(tài)可以被保留下來。該被替換的組件替換了,這一點之所以能夠?qū)崿F(xiàn),是因為 UI 在內(nèi)存中有一種中間態(tài)的表現(xiàn)形式,它就是人們說到的 Virtual-DOM。這是用來說明 Virtual-DOM 作用的一個例子。另一個例子是,如果我們現(xiàn)在要將一個完整的動畫系統(tǒng)集成到 React 中,我應(yīng)該怎么做。比如我們現(xiàn)在要做一個手勢拖動觸發(fā)的動畫,我們肯定不希望每一幀都去做渲染,我們希望只計算幾個版本的 UI。假定最左邊是 0% 的版本,最右邊是 100% 的版本,我們計算好幾個類似的關(guān)鍵幀,在拖動的時候就可以利用插值計算出當(dāng)前 UI 樣子。但問題又來了,你怎么去生成那些關(guān)鍵幀呢?你需要一個 UI 在內(nèi)存中的表現(xiàn)形式,這樣你才能在兩者之間做插值。這個例子也說明了 Virtual-DOM 的意義,有些特性離開它就沒法實現(xiàn)。所以 Virtual-DOM 與性能無關(guān),它的存在只是為了讓一些特性變得可行,我們認(rèn)為這種 UI 在內(nèi)存中的表現(xiàn)形式還是很重要的。盡管在一些綜合性測試?yán)锩?,我們可能會比其他方案?10% 左右,但你應(yīng)該明白,這并不是一個問題。至少在我們的測試中,當(dāng)我們分析 Facebook 一些復(fù)雜頁面渲染的時候。我們親眼看到的是,React 只花費了 10% 的時間,另外 90% 的時間開銷是應(yīng)用代碼導(dǎo)致的??蚣苣軌騼?yōu)化的,可能也就只有 2% 的速度。所以當(dāng)你去看那些測試的時候,測試代碼可能有 1000 行,但是只有一個 component。你可能就只關(guān)注到了那 2% 的差異,但它并不能反映應(yīng)用的實際表現(xiàn)。所以真正影響性能的是整個 app 如何工作,以及我們?nèi)绾文茏層脩舸a運行的更好。這就是 Concurrent Rendering,Server Component 以及所有新特性存在的意義。我們要去支持更大規(guī)模的用戶代碼,而不是試著去贏下這些基準(zhǔn)測試比賽,有些基準(zhǔn)測試只有一些不到 10 行的小組件, 它們不值得我們付出時間和努力。
主持人:最近有很多新的庫出來了,人們想知道 React 如何做到跟上潮流,保持競爭力。
Dan:是的,我想我已經(jīng)從某種角度上回答了這個問題。我們正在努力從全局出發(fā),用更加通用的方式去處理那些從單點很難以解決的問題,比如說 data-fetching,代碼分割,未來還有動畫以及其他的功能,React 在將來能讓它們的實現(xiàn)變得更簡單。我猜這就是 React 競爭力的來源吧。不過我個人覺得 React 并不需要某些特性來讓它“保持”競爭力。比方說當(dāng)我要用 React 做一些原型的時候,我要去畫一些 UI,React 用起來會很自然,很順手。即便 React 在將來五年沒有新的 feature,我也會覺得使用嵌套的函數(shù)來表述 UI 是一件很自然的事情。我覺得這種開發(fā)方式很合理,我也很喜歡 React 現(xiàn)在的樣子,所以我并不覺得 React 要變得更加 “有競爭力” (Dan 用兩只手比劃了引號)人們才會使用它。但我還是要重申一下,我們現(xiàn)在正在做的很多功能,可以讓當(dāng)前復(fù)雜的開發(fā)工作簡單化,我對它們的存在感到興奮。
SSR、CSR、NSR、ESR
主持人:Vue 和 React 都在解決網(wǎng)頁渲染的問題,但是當(dāng)前渲染網(wǎng)頁有很多種方法,像是 SSR(Server Side Rendering), CSR(Client Side Rendering), NSR(Native Side Rendering), ESR(Edge Side Rendering),你是怎樣描繪未來五年前端的發(fā)展的呢?
Dan:這個問題是說,你有很多種不同的方式來運行你的代碼,你可以讓它在客戶端運行、在服務(wù)端運行,或者在其他地方運行,問題在于你如何去組織它們。但我覺得這里的大部分工作應(yīng)該都會由框架來完成,所以再說一遍吧,我還是推薦你去使用框架。像 Next.js 就是一個不錯的選擇,它能讓你對這部分如何實現(xiàn)有一個大體的印象。Next.js 可以通過對 React 現(xiàn)有概念的包裝來簡化這部分的操作,比如你要使用 Server Component 的話,Next.js 有他自己的 API,getServerSideProps() 或者是類似的方法,你不需要使用 React 原生的方式的去組織項目,Next.js 會通過它自己的 API 將你的項目編排好,讓 Server Component 等類似的功能生效。所以我覺得未來... 哦我突然想到,如果你對 Server Component 感興趣的話,不妨去看一下 Shopify 家最近新出的框架,Hydrogen。他們最近放出了一個 Demo 演示,如果你搜索 「Shopify Hydrogen Demo」 或者類似的關(guān)鍵詞就能看到,里面演示了他們是如何使用 Server Component 的,這也是對未來場景的展望吧。如果你只有一個渲染樹,比方說你在寫頁面或是寫個博客網(wǎng)站,你只需要去在服務(wù)器端的文件系統(tǒng)中讀取一些 Markdown 文件,然后將它們渲染到組件的對應(yīng)位置,最后把渲染好的組件傳遞給客戶端,你只需要考慮組件就 OK 了。至于在哪里執(zhí)行代碼邏輯,這完全是由你自己決定的。有些可能是在構(gòu)建的時候執(zhí)行的,有些頁面如果你愿意的話也可以在服務(wù)器端運行,只有那些與實際交互相關(guān)的代碼會被下發(fā)到客戶端,然后在客戶端運行。理想情況下,這整個流程還是一個單一的渲染樹,你不必去實時關(guān)注這部分的差異。你只需要給一些小提示,比如修改一下文件的擴展名,代碼就會自動地在最合理的位置去執(zhí)行。所以你不用想那么多,想自己既要做服務(wù)端渲染,還要做客戶端渲染,有可能還要其他端的渲染。框架會幫你把這部分搞定的,你只需要使用同一個范式來寫代碼,它在所有位置都可以生效。
React 與框架
主持人:如何評價「React 更像是一個系統(tǒng),而非一個框架」這種說法?
Dan:我不會說 React 自身是一個框架,我認(rèn)為這個說法并不公平。首先我認(rèn)為 React 只是一個庫,因為它并沒有去約束你工作的方式,沒有去約束你項目的結(jié)構(gòu),它只是給你提供了工具,讓你能夠去構(gòu)建組件。但我確實覺得 React 正在成為一種架構(gòu)(Architecture),但這和框架又有所區(qū)別。因為想要新建一個 React 的框架其實有很多種方式,但是現(xiàn)在 React 對某些技術(shù)的實現(xiàn)也有了自己的「觀點」,比如應(yīng)該如何進行 data-fetching,如何去做路由,如何去做服務(wù)器端渲染,這些功能應(yīng)該怎么組合起來。React 只是一種構(gòu)建 UI 的方式,而不同的框架可以基于這點為用戶提供更加上層的能力。
吸引前端開發(fā)者特質(zhì)
主持人:你認(rèn)為好的科技公司最吸引前端開發(fā)者的特質(zhì)有哪些?能不能簡單列舉兩三個?
Dan:嗯,我想一想。我覺得最重要的一點是「要能夠從身邊的人身上學(xué)到東西」。對我來說,有一個能夠無時不刻學(xué)習(xí)新事物的環(huán)境是最重要的。當(dāng)然這不是說你要去不斷學(xué)習(xí)新的庫,不要因為對前端這一領(lǐng)域全貌的不了解就說「前端一直在變化」這種話。我認(rèn)為事實并不是這樣的。正如我說的,大多數(shù)新事物都只繼承了舊的思想,雖然層出不求,卻只有相同的本質(zhì)。如果你往更深的地方去探究,你就會發(fā)現(xiàn)它們都是同一個東西。但我覺得理想的環(huán)境就是,公司 / Team 鼓勵你去學(xué)習(xí)新的知識,團隊中有 10 年或者 15 年工作經(jīng)驗的前輩,你可以從他們那里獲得收獲。組內(nèi)的高度自治也很不錯,你不會被安排去做特定的工作,你可以從任務(wù)清單中完成自己想做的工作,這一點也會讓工作更有趣。被動的激勵自然很重要,但如果你能夠發(fā)揮主觀能動性,作出自己的選擇,那也是非常有價值的。我不知道這是否回答了你的問題。
如何學(xué)習(xí) React 代碼
主持人:很多朋友對你的個人經(jīng)歷感興趣,你剛加入 Facebook 的時候是如何學(xué)習(xí) React 的結(jié)構(gòu)、概念,并慢慢開始貢獻代碼的呢?
Dan:React 有一個相當(dāng)復(fù)雜的 codebase,里面有很多復(fù)雜的上下文導(dǎo)致很難上手。一般來說當(dāng)有新組員加入的時候,我們會花很多時間陪他們一起看一遍代碼。剛開始他們可能會做一些小的 bug 修復(fù)或者相對獨立的小功能點,來慢慢地熟悉代碼。整個流程最關(guān)鍵是要熟悉架構(gòu),一旦你對整個項目的架構(gòu)有了充分的了解,接下來的所有工作就都順理成章了。有一個對我?guī)椭艽蟮狞c,那就是去查看人們的 Issue,并去解決他們。在不同的時間點上,我都會過一遍現(xiàn)在處于 「Open」?fàn)顟B(tài)的所有 Issue,看看自己是不是能夠解決這些問題,思考一下自己是不是能夠理解他們在說什么,如果不懂的話就去學(xué)習(xí)上下文。我想我個人可能已經(jīng)看了數(shù)千個 Issue 了,如果你想要快速上手項目的話,我認(rèn)為這是一個非常不錯的學(xué)習(xí)方式。你可以點擊查看處于「Open」?fàn)顟B(tài)的 Issue,應(yīng)該差不多有 500 個,你可以從頭看,也可以跳轉(zhuǎn)到最后一頁從最老的那個開始看。通過看 Issue 你逐漸就能理解當(dāng)前有哪些問題,慢慢地去理解代碼,理解項目的更新歷史等等,所以這就是通過 Issue 學(xué)習(xí)的方法。幫助提出 Issue 的人,在我看來是做貢獻的最好方式,實話說我們并不需要人們?nèi)ヘ暙I那么多的代碼,通常 Review 代碼也需要花費我們很長時間,而且人們其實很難把功能寫對。所以當(dāng)我們收到社區(qū)提交的代碼的時候,我們其實并沒有從中收獲很多。但替我們回答人們的 Issue 確實對我們很有幫助,有時候用戶提交了一個 Bug 報告,但實際上是他們自己寫的代碼有問題。如果社區(qū)中有人幫助他們發(fā)現(xiàn)了問題,找到了 bug,我們就不用再在這些 Issue 上花費時間了,這也是我最歡迎的貢獻方式。
維護 React
主持人:React 有一個非常龐大的 codebase ,請問 React 開發(fā)組和社區(qū)是如何維護如此復(fù)雜的代碼倉庫的?
Dan:代碼倉庫確實帶來了一些挑戰(zhàn),但是有挑戰(zhàn)的原因不是因為代碼倉庫大,而是因為一些其他的原因。首先你要知道怎么去進行開發(fā),怎樣把代碼跑起來。舉個例子,我們依賴了非常多的自動化測試,大概有數(shù)千個測試要跑吧,我覺得數(shù)量可能在 5000 個以上。目前我們寫的測試代碼可能比源代碼還要多,我們非常依賴這一點。我們從中學(xué)到的一點是:一定要去針對 React 的 public API 寫測試腳本。我們之前的做法是對獨立的模塊進行單元測試,但這對 React 這種項目來說是一個非常糟糕的想法,因為一旦你要重寫 React,那些針對老代碼的測試用例就沒用了。在我們重寫 React 的過程中,我們不斷地意識到「哦,又有一堆測試代碼不能用了,因為之前的代碼不存在了」。所以我們把所有的測試用例修改成了僅對 public API 進行測試,來模擬用戶的實際行為。測試用例只能用 ReactDom.render() 或者類似的方法,并不能訪問內(nèi)部的 API。在只針對 public API 進行測試的情況下,就算我們替換了原有的文件,測試樣例也照樣能夠跑通,還能順便測試我們的重寫是否是正確的。這算是我們從實踐中總結(jié)出的經(jīng)驗吧。另一個有趣的點,也可能是比較有爭議的一個點,就是我們有很多文件都存在兩個版本。如果你看源碼的話,你會發(fā)現(xiàn)我們有 .old.js 或者 .new.js 這種文件。這些文件基本上是復(fù)制粘貼出來的,它們的內(nèi)容也基本相同。我們用它們來測試一些可能會帶來風(fēng)險更新,對于 Facebook 網(wǎng)站,我們可以同時部署多個版本。我們有時候會將這些實驗性的更新寫到 .new 文件里面,然后在 Facebook 的實驗環(huán)境里面進行回歸測試,如果測試各項指標(biāo)沒有劣化的話,再將這些更新復(fù)制到 .old 文件中去,所以說我們的網(wǎng)站在任何時刻都有兩個版本。在實驗測試的過程中,其他人也可以去做其他部分的代碼提交。這聽上去可能比較奇怪,但實際用起來效果還是不錯的。
主持人:所以這就是你們在開發(fā)中保持 React 代碼質(zhì)量的秘訣嗎?
Dan:是的,我覺得是 Facebook 的測試環(huán)境真的非常好,我們不僅有針對 React 倉庫本身的測試,還有很多針對 Facebook 進行的測試。有時候我們在 React 的開發(fā)過程中把功能搞壞了,我們可以在測試環(huán)節(jié)發(fā)現(xiàn)問題。在生產(chǎn)環(huán)節(jié)中,甚至是生產(chǎn)環(huán)節(jié)之后,我們都可以部署實驗測試,然后去觀察哪些指標(biāo)出現(xiàn)了下降。比如我們?nèi)ツ晔逻M行了一次重構(gòu),那之后我們不得不將手頭的工作暫停了兩個月,因為我們看到某些指標(biāo)下降了 1%,我記得好像是網(wǎng)站的評論數(shù)之類的少了 1%。我們就要查清楚到底是由性能問題導(dǎo)致的,還是因為 bug 或者其他什么原因。你要知道,其他的框架往往做不到這一點,它們往往需要先發(fā)布一個版本,然后可能一年之后才會有人發(fā)現(xiàn)里面的 bug,然后上報。但我們不會這樣做,我們要確保 React 的高質(zhì)量,所以我們花費了數(shù)月的時間來查這個問題。用二分法不斷地分割 commit 提交,不斷地去做實驗測試,甚至要精確到每個 commit。最終,我們找到了 bug,我們部署的測試環(huán)境中確實有一個 bug。當(dāng)我們將其修復(fù)之后各項指標(biāo)就再次回歸正常了,這個結(jié)果也給了我們信心。你要知道,在 Facebook 這種體量的公司中,即便只有 1% 的指標(biāo)劣化,也會影響數(shù)百萬人。所以如果有大的問題的話會比較容易發(fā)現(xiàn)。
閱讀 React 源碼?
主持人:作為一個使用 React 的前端開發(fā)者,我們需要去閱讀 React 庫的源碼嗎?如果需要的話,有沒有好的閱讀代碼的方式?
Dan:我覺得沒有必要,這可能會是一項相當(dāng)困難的工作,因為我們沒有在任何其他地方提及 React 自身的架構(gòu)是怎樣設(shè)計的。如果你上來就開始讀代碼,你可能會感到非常困惑,不明白為什么這樣設(shè)計。這可能也是我們將來需要改進的一點,將來到了某個時間點,我們可能會去解釋這里面的實現(xiàn)原理。但我覺得如果你只是想玩玩的話,這個過程應(yīng)該也算不上痛苦。比如我自己就很喜歡做一件事,用 debugger 的步進功能(step-in) 來一行行跑代碼,看看代碼會跑到哪個函數(shù),運行代碼會用到哪些不同的文件。另一件你可以做的事是使用 Chrome Performance Tools,你可以打開 Chrome 的 Performance Tab,點擊錄制,然后在你的應(yīng)用中進行一些操作,之后點擊停止,你會看到一張火焰圖或者火焰表。這個分析結(jié)果非常有用,它就像是某種堆棧,你可以看到函數(shù)的調(diào)用順序,看到代碼中正在發(fā)生的事。它常用來測試性能,你可以看到你代碼中的哪一部分運行的比較慢,但你也可以用它來做一個當(dāng)前函數(shù)總覽,因為上面展示了函數(shù)的名稱。你可以看到狀態(tài)變化會引發(fā)哪些不同的事情。你可能會發(fā)現(xiàn)「哦?這個函數(shù)在所有的地方都被調(diào)用了,它是做什么的?」。之后你可以點進去,看看里面到底執(zhí)行了什么。沿著這種性能測試來一步步探索代碼我覺得也是一個不錯的學(xué)習(xí)方式,可以了解到 React 在哪部分花了時間,哪些函數(shù)是其核心之類的。
保持對 React 熱情
主持人:你是如何保持對 React 的熱情的?
Dan:我就是很喜歡,不知道為啥,仔細想想的話,可能是因為 React 非常符合我對 UI 代碼的看法吧。在進入 Facebook 之前,我就開始使用 React 了,那時候我還在一家小的創(chuàng)業(yè)公司。我們當(dāng)時在開發(fā)一個非常復(fù)雜的應(yīng)用,試著將它從 Backbone 遷移到 React。我們遷移不是因為當(dāng)時 React 是大趨勢,而是因為當(dāng)時用 Backbone 開發(fā)一個復(fù)雜的 UI 真的非常的困難,相比起來用 React 來實現(xiàn)真的是太簡單了。其中心思想就是寫一個狀態(tài)的函數(shù),來表述當(dāng)前屏幕上應(yīng)該展示哪些東西。這也是我常常問自己的問題,我的組件應(yīng)該長什么樣子,哪些內(nèi)容應(yīng)該展示在屏幕上。這種思想和我的編程思路天然就是契合的。但確實有些東西不太好歸納到這個范式里邊,比如 data-fetching 就是一個典型。你真正想要考慮的是屏幕上有哪些內(nèi)容,但一涉及 data-fethcing,你就要去思考如何與服務(wù)端通信、怎么等待服務(wù)端返回結(jié)果、等待的時候可能還要設(shè)置某個狀態(tài),這樣用戶再次發(fā)起請求的時候才能忽略掉上次請求的結(jié)果。我原本只想考慮哪些東西應(yīng)該展示在頁面上,但這些東西卻將問題復(fù)雜化了。這也是我們想要為用戶提供 data-fetching 能力,比如 Suspense 功能的原因,它可以幫助你減少思考問題的復(fù)雜性。我只要考慮想要看到什么,從哪里獲取,即便是外部 URL 也不用去考慮時間。我只想要表達目前屏幕上存在哪些東西,之后交由 React 決定如何去展示它們。我覺得讓我非常激動的一點是,現(xiàn)在 React 已經(jīng)能夠很好地實現(xiàn) UI 的組合與嵌套了,但是還有 data-fetching,動畫,代碼分割,data-asynchronous 這些目前難以實現(xiàn)的東西,我希望這些功能能變得更加簡單易用。我希望在五年以后,我們能夠用更加簡單的方式構(gòu)建復(fù)雜的應(yīng)用,而這份簡單來源于 React 幫助用戶處理了這些復(fù)雜性。這就是我的想法。
如何像你一樣優(yōu)秀
主持人:如果我想要變得和你一樣優(yōu)秀,有沒有什么好的前端學(xué)習(xí)資料可以推薦的?
Dan:我不確定自己算不算優(yōu)秀,我其實在很多方面都沒有跟上時代的腳步。比如,如果你讓我去做一個好看的應(yīng)用,可能很難去完成。因為我對 CSS 的知識還停留在 2010 年,我對于 CSS Grid 和 Flexbox 也并不是非常了解,我不知道這是不是你希望聽到的。但是如果你需要我推薦學(xué)習(xí)資源的話,我覺得一個很有幫助的點是你可以去挑選一些 UI 的樣例,然后從零去實現(xiàn)它們。這個過程中不要去使用 React,也不要去使用其他任何庫。比如試著去實現(xiàn)一個帶自動補全的輸入框,或者是對話框中的一個 tab 之類的,體驗一下完成這些操作的復(fù)雜度。另一點我很喜歡的是做一些小游戲,這也很有幫助,比如做一個井字棋,或者是貪吃蛇。做游戲會推動你去思考,思考程序如何去設(shè)計,思考如何去解決問題,而這一點是你平時寫表單、寫界面所訓(xùn)練不到的??偨Y(jié)來說,我推薦你做一些體量小,但是有深度的東西,然后從中獲得收獲吧。
如何度過閑暇時光
主持人:請問工作之余,你是如何度過你的閑暇時光的?
Dan:我工作之余并沒有做太多有意義的事。我過去非常愛玩堡壘之夜,我玩的其實并不是很好,但還是玩了很久。我建筑建的很爛,如果有人打我,我就建一堵墻,但通常我都會被嚇一跳,然后手忙腳亂地溜走。但我其實也有一陣子沒玩了?,F(xiàn)在的話一般就聽聽歌,散散步,做一些業(yè)余項目之類的。
justjavascript.com
主持人:你寫了一個 「Just Javascript」 的系列文章,我個人也非常喜歡這個系列,已經(jīng)等不及要看下一期了,想問一下新文章的進展。
Dan:好的,有些朋友們可能還不知道,這其實也是我個人的業(yè)余項目,叫做 justjavascript.com。它像是一個 JavaScript 的課程,它現(xiàn)在還是免費的,但是再過幾周可能就不免費了。這個課還是很特別的,它不像其他課程一樣用傳統(tǒng)的方式講 JavaScript 的知識,它更多是去教你怎么理解代碼,課程里面有很多可視化的東西,比如動畫呀、圖表呀之類的。它也會教你去從零實現(xiàn)一些東西。我想要通過它告訴人們?nèi)绾稳フ_地閱讀代碼,如何正確地理解代碼的運作方式。當(dāng)然我們也在制作一些新的內(nèi)容。現(xiàn)在我們正在將整個課程打包,然后上傳到網(wǎng)站上,完成后這將是一個付費課程,你購買后可以看到里面的內(nèi)容,所有的課程、繪圖與測試問題都會呈現(xiàn)在網(wǎng)站上。我們還不確實是否會有人買這個課程,如果這樣做能夠賺錢的話,我們可能會更新更多的內(nèi)容。這個項目之前一直是免費的,已經(jīng)有一年半的時間了,我們想要看看它是不是一個可行的商業(yè)化產(chǎn)品,之后再決定如何去運營它。這個項目幾周后就會正式上線,想要支持的朋友可以關(guān)注一下。
對中國開發(fā)者說點什么
主持人:有沒有什么想要對中國開發(fā)者們說的話?
Dan:我不知道該說點兒啥。我不確定在中國有多少人在用 React,我只知道 Vue 在中國非常的流行。但我覺得有更多的選擇是件好事,我非常感謝那些 React 文檔的翻譯者們,以及很多 React 庫的中國開發(fā)者們。我不知道 React 能不能在中國流行起來,這個遠在異國的我們可能影響不了。但是如果你對 React 非常感興趣,你們有機會改變周圍的環(huán)境,讓它流行起來。如果 React 流行起來,以后找工作可能會更容易吧(笑)。我們很高興看到人們翻譯博客文章,傳播知識,舉辦會議,真心地感謝為此付出的每一個人。
主持人:你今后有沒有想要在中國的 React 社區(qū)中更活躍一點,我們其實很想跟你多多交流。
Dan:當(dāng)然了,我其實也很想,但是不知道怎么做。正好有你們邀請了我,我感覺這次活動很酷,之后我們可以更經(jīng)常地交流。
主持人:好的 ,我這邊問完了所有觀眾的提問,非常感謝 Dan 陪我們進行了這次漫長的在線對話。
Dan:感謝你們邀請我。
主持人:感謝,我們下次再見!
Dan:再見!
附錄
| 英 | 中 |
|---|---|
| State Management | 狀態(tài)管理 |
| Single Page Application | 單頁面應(yīng)用 |
| Immutability | 不變性 |
| Spread Operator | 擴展操作符 |
| Funtional Programming | 函數(shù)式編程 |
| Funtional-lite programming | 輕函數(shù)式編程 |
| Data-fetching | 數(shù)據(jù)獲取 |
| server-rendering | 服務(wù)器端渲染 |
| Flame gragh | 火焰圖 |
| Tic-tac-toe | 井字棋 |
| Snake game | 貪吃蛇 |
| Fortnite | 堡壘之夜 |
你說喜歡你的人,真的能忍住不找你嗎
我堅持不找你,不是因為我不想你
更不是因為我不愛你
而是因為你給我的感覺
像是我在打擾你
可能我這個人 太過于自尊了吧
我是那種你不主動找我
我這輩子都不會 再跟你有交集的人
但是你只要主動跟我說一句話
哪怕是一句在嗎
我也會立刻秒回你
只要你跟我說 你想見我 就算是刀山火海
我也會以最快的速度 立刻出現(xiàn)在你的面前
但是很可惜 你沒有找我 所以我也不會再出現(xiàn)在你的世界里面
一扇不為你開的門,你一直敲,一直敲
是不禮貌的
