展望 React 17,回顧 React 往事

原文: https://zhuanlan.zhihu.com/jheaven

至 React 16 正式發佈已經過去了一年,回望 React 16 當時帶來的變化,如 Fragment,Portal,Error Boundary,SSR 優化等等期盼已久的 feature。最重要的其實還是 new architecture (Fiber) 的平穩落地。雖然在這之前的很多公開場合,React core team 的人已經多次談論到這個新的架構,但是大家的關注點往往會被更上層的形式化的東西所吸引(就如同新的 React Fire 中大家更關心 className -> class 一樣),當然了,這個不上一兩句話能說清楚的,要展開講就有點要扯皮了,我們這裡就不開會了。

回到 React 16 的話題。要討論未來(React 17),必須要了解過去。以 React 16 為分水嶺,我們可以分為兩方面來看這個問題。

  • 一是為什麼
  • 二是怎麼辦

1. 為什麼?

「是不是」這個問題我們就不討論了,如果筆者沒有穿越的話,應該是「是」的。

為什麼要進行這樣一次內核的架構調整或者說完全重現呢?我們能夠找到的資料基本是從 Seb(Sebastian Markbåge) 提出 New Core Algorithm facebook/react 開始的。然後被熟知是通過 acdlite/react-fiber-architecture 。

展望 React 17,回顧 React 往事

https://github.com/facebook/react/graphs/contributors

Seb 是誰呢,其它的頭銜這裡就不展開了,熟悉 React repo 的人應該知道,16 年以後,即從 16 架構的提出以及至今整個最核心代碼的設計和部分書寫,絕大部分是由 Seb 來決定的。當然啦,這裡沒有否認其它人的勞動成果的意思,但是從客觀上我們要知道這麼一件事。

展望 React 17,回顧 React 往事

https://twitter.com/dan_abramov/status/996755754215530496

咳咳,扯得有點遠了,回過頭來。最初提出的時候,我們可以看到,這只是一個針對 reconciliation 階段的重構的算法,注意一開始並沒有提到 Fiber 這個概念。為什麼要重構呢,很簡單嘛,一些新的 feature 現有的算法不好弄,甚至沒法弄。兩個月後,在 facebook 上 Seb 正式提到了 Fiber 這個概念。到後來演變為對整個框架的重寫。其中解釋了為什麼要進行重寫:

Once you have each stack frame as an object on the heap you can do clever things like reusing it during future updates and yielding to the event loop without losing any of your currently in progress data.

  • reusing it during future updates: ReactChildFiber.js#L303
  • yielding to the event loop without losing any of your currently in progress data: ReactFiberScheduler.js#L1121

這些都已經體現在了目前的 React 代碼中。

展望 React 17,回顧 React 往事

找不到 youtube 鏈接了,還望大家告知

說了這麼多,到底有什麼用呢?其實說到底,React 所做的一切(包括現在以至將來)的首要目的都是為了一件事:「用戶體驗」。只要從這個出發點入手,就能明白它的用意。(當然第二肯定是「開發體驗」了)

注意這裡的用戶體驗是框架層面的,不是 UI 設計層面的。對於框架而言,關注用戶體驗體現在兩個方面,一是「快」,二是「流暢/自然」。

「快」很好理解,之前我 diff 要 800 ms,現在只要 500 ms,自然就快了。(怎麼做呢,我們在第二點「怎麼辦」中再講)

而「流暢/自然」這個就比較難理解和麻煩了。首先不知道它指的是什麼,頁面流暢,更新流暢,還是交互流暢?其實是一個問題。我們首先想想,假如用戶用的都是超級無敵計算機,計算斐波拉切的 1E 項只需要 1ms,只要我們不搞個像死循環這樣的對吧,很多問題都沒有了。

但是問題是用戶用的是小米 2 (主要是上週遇到個 bug 是這個的。。)這樣的機器,這還不要緊,最重要的,我們是依賴於

瀏覽器的。即,JS 本身的單線程(不要提 worker 和 stage 0 的一些提案了朋友們,注意這裡的語境,後面不再闡述)的限制,加上瀏覽器自身(event loop)以及後臺的多種工作的協調的限制。我們必須面臨如下的問題:

展望 React 17,回顧 React 往事

https://github.com/tdresser/should-yield#the-problem

其中的第二點尤為重要,雖然這個圖和 React 沒什麼關係,這是 chrome 的人提出的(雖然可能也參考 React)。但是這一點是說到根本上的問題之一了,即如何快速響應用戶的交互。舉例來說,用 React 以前的這種同步地遞歸式的方式,第一,無法在中途結束或者說停下來。第二,無法分成 chunk 去執行。造成的後果是,卡(主線程)和掉幀的風險增加。


總的來說,這便是主要的問題。日益降低的用戶的忍耐力同落後的用戶體驗的矛盾已經代替了之前的日益增加的智能設備數同落後的生產力的矛盾。

所以 React 所在思考和解決的,本質就是如何實現更好的用戶體驗。這個筆者在如何評價React的新功能Time Slice 和Suspense?已經提到過。

當前了,生產力也是需要兼顧的,JSX 和 class component 在這之前已經首當其衝了。後面16 的 Fragment, .....。16.x 的 new context, new ref, new lifecycle api, profiler。17 的 .....(後面再說)。這些也反映了對開發者的人文主義關懷。

2. 怎麼辦?

好的,囉嗦了這麼多,問題有了,咋做呢?

我們先不慌,我們先思考下,這些問題是 React 最先發現的嗎?又僅僅是 React 需要解決的嗎?

肯定不是啦,瀏覽器也意識到了這個問題,比如 chrome 很早在 timeline/performance 面板裡就有 jank frame 的紅色警告。而開發者也可以通過 w3c/longtasks 來檢測。也包括其它的一些提案比如 first-input-delay 等等。但是這都是手段,沒有解決根本問題,當然啦,也主要是解決不了,畢竟這是用戶端(開發者)自己才能解決的事,所以更好的方式也是放到框架層面來解決。

所以具體到 React 要解決這些問題,就需要做到(雖然這個圖也和 React 沒有關係,但是我們還是可以用它來說明問題。):

展望 React 17,回顧 React 往事

https://github.com/tdresser/should-yield#the-problem

  1. a unit of work 或者說 chunk:想想要是以前的遞歸,這就完全沒得搞了(當然也可以,只是很麻煩,總之弊大於利)。所以重寫的第一步,改變內核的數據結構,即現在的 fiber(我們知道 fiber 是一種數據結構,當前還有另外一層含義)。改了之後第二步就有希望了,即將遞歸改成循環,然後我們就能一個一個處理了(至少在數據結構上更方便了,形式上還需要其它的變化)。也就是源碼裡的 performUnitOfWork 。
展望 React 17,回顧 React 往事

https://twitter.com/pomber/status/919937964104437761

fiber 的數據結構的應用,是 React16 的本質更新,而 Async Render 以及其它一些 feature 是 React17 的本質更新,所以從本質上來說,React 16 是 React 重構過程中的一箇中間形態和畢竟過程。(畢竟一口吃個餅容易噎著。。)

2. continue the work:continue 就意味著兩件事,interrupt 和 resume/continue。當然,也就意味著這是異步的了。這個畢竟複雜,我們放到後面 async render 的地方單獨再講。


ok,到現在我們整體粗略的介紹了下 React 16 之前的現狀和 React 16 所做的努力。接下來我們就需要介紹 React 16 之後到 React 17 的變化了。


那麼現在 React 16 已經發布了,我們前面說過這只是 React 重構過程中的一個分水嶺,React 的最終目標還沒有達到,那麼 React 最終的目標是什麼呢?

我們可以簡單的概括為:Async render(完整的應該叫 Async Rendering,這裡簡化下)。


在講這個之前,我們先回顧下我們之前談的第二個目標:「流暢/自然」

那麼怎麼讓瀏覽器的一切活動流暢呢,要回答這個問題,我們不妨從反方向思考,即如何讓瀏覽器卡頓呢,這樣就很簡單了,只需要我們在對交互行為(不管是來自用戶的交互還是 DOM 本身的動畫)做出響應的時候消耗過長的時間,這樣到瀏覽器繪製新的界面(即交互動作完成後更新後的界面)給用戶看的時候,就有了一個時間差,用通俗的話來講,就是用戶感覺卡了。

我們在玩遊戲的時候可能會對此有更直觀的感受,比如就玩魂鬥羅或者超級瑪麗吧,你按了一下發射子彈的按鈕,但是畫面上並沒有看到子彈,1 秒鐘過後,敵人死了。。或者你在橋的這一頭,按了半天前進按鈕沒反應,你沒有移動,然後突然發現你已經在橋的這一頭了。。


舉例來說,比如一個純數字的輸入框,輸入的數字代表要在界面上顯示多少個氣球。當我按下 1,接著按下 2 的時候:

  • 以前的方式:必須等到 1 被處理完了之後,才能響應 2。這種響應體現在兩個層面,一個是輸入框裡的數字的更新。一個是界面上氣球的個數的更新。所以,如果處理 1 消耗的時間過長,那麼就會出現非常糟糕的用戶體驗。即,當我按下 2 之後,一段時間內輸入框裡並不會出現 2,界面上的氣球也不會變多。而當它更新和變多之後,我已經按下 3 甚至 45678 了。。實際上每次消耗的時間都比較長的話,中間的狀態就全部丟失了,俗稱丟幀,也就是上面提到的你看到的時候敵人已經死了,或者你已經在橋的這頭了。比如 4 後面按了 5,6,7,8。你看到的是一瞬間 5678 已經都在屏幕上了,而不是按下 5 就顯示 5,按下 6 就顯示 6。
  • 理想的(現在的)方式:當我按了 1 之後按下 2,用戶期待的其實是先顯示 1 個氣球,然後顯示 12 個氣球(注意這就是為什麼不能用 debounce 來代替)。


瀏覽器環境也是類似的道理。所以要想避免這種情況,我們需要做的就是:

  • 不要妨礙瀏覽器自己的渲染更新邏輯(即 60 FPS 的幀渲染)。(一個消耗時間太長的任務就會妨礙瀏覽器的正常渲染工作,使它掉幀)
  • 但是偉大的毛主席教育過我們,又要馬兒跑,又不給馬兒吃草是不行的。這也就是 Dan 說的:It's the same amount of work overall, so if it's not async, then it's sync and blocks the thread.(筆者譯:總的工作量是一樣的,所以如果它不是異步的,那麼就必然是同步且阻塞的)。所以消耗時間太長的任務不應該怪罪在它本身消耗時間長(加上不是不合理的消耗),所以需要把它分割成很多小的片段,每次執行一點(避免阻塞造成掉幀),同時在下一次執行的時候,能夠充分利用之前的執行的結果,從而盡最大努力減少工作量。
  • 光靠利用之前,效果還不夠,工作量是沒法再減少了,但是馬兒會不會沒吃夠呢?於是 React 的人自然也想到了利用空閒時間預渲染。熟悉的同學應該會想到瀏覽器早就有這招了,即 resource hint api 裡的 preconnect, prfetch, prerender(雖然已經被廢棄)等等。


所以為了實現這樣的目標,React 將工作流劃分為了兩個階段,Render 階段和 Commit 階段。

Render phase & commit phase

Render 階段是可以被中斷和分割的,那麼怎麼把設置 `innerHTML`,`textContent` 這樣的東西分割出來呢。React 採用的方式是 effectTag 。

bvaughn:What is meant within the README of `create-subscription` by async limitations? Can it be clarified? · Issue #13186 · facebook/react
- The render phase determines what changes need to be made to e.g. the DOM. During this phase, React calls render and then compares the result to the previous render.
- The commit phase is when React applies any changes. (In the case of React DOM, this is when React inserts, updates, and removes DOM nodes.) React also calls lifecycles like componentDidMount and componentDidUpdate during this phase.

筆者譯:劃分 render 階段和 commit 階段的意義是:

  • 組件在 render 階段發生錯誤,React 能安全的丟棄正在處理中的任務,然後讓 Error Boundary 去決定到底渲染什麼。
  • 如果有很多的組件需要 React 去渲染,React 能夠將這些工作分割成更小的 chunk 執行,從而避免阻塞(block)瀏覽器。一旦所有的組件被渲染完畢(筆注:指 React 自身的 render,而不是渲染到界面上),react 能夠同步地提交(commit)這些工作。比如,DOM 的更新。(這是新的實驗性的 async rendering 模型的核心)(筆注:即異步 render,同步更新)
  • React 能夠對任務劃分優先級。如果低優先級的任務被處理的同時,更高的優先級的任務被調度了,React 能夠安全地暫時擱置或者說暫停低優先級的任務,轉而去處理更高優先級的任務。因為 React 只在 commit 階段應用更新到 DOM 上,所以它不需要擔心留下一個只有部分狀態被更新的應用(筆注:即只更新需要更新的狀態裡的一部分並不會反映在 UI 界面上,所以不會出現界面上一部分更新了,一部分沒更新,只有當所以組件更新完畢後才會一起 commit)

所以在源碼中我們可以看到,在 Render 階段 React 只給 fiber 打上各種 `effectTag` 標記,並不會進行任何實質的 DOM 操作,因為實際對應的 DOM 操作放到 commit 階段去進行。


具體到代碼層面怎麼實現呢?答案就是 custom requestIdleCallback based on requestAnimationFrame。

Async Render

展望 React 17,回顧 React 往事

https://medium.com/@paul_irish/requestanimationframe-scheduling-for-nerds-9c57f7438ef4

展望 React 17,回顧 React 往事

https://medium.com/@paul_irish/requestanimationframe-scheduling-for-nerds-9c57f7438ef4

瞭解了上圖 rAF 的過程,我們就可以知道,在一幀的空閒時間裡分配給我們執行 js 的時間是有限的,如果我們執行 js 超過了這個時間,就會造成 lag,rAF 保證不了不超過,因為 js 是我們在執行。因此React 的進行了一些優化,自己封裝了一下 rAF 從而實現了 rIC,如果超過了 rIC 被分配到的時間(通過 rIC 的第二個形參 `timeout` 判斷即可,具體可以看規範),就暫停任務,則會到下一次執行任務的時候再去執行(和嵌套 rIC 或者 rAF 的表現是一致的,即嵌套的 rIC 會被放到下一個 rIC 中去執行,而不是當前的),但是瀏覽器自己的 rIC 有很多不適合的地方,沒法用,所以才需要根據 rAF 自己封裝了一下,實現了 rIC 的功能,同時更加細粒度。(當然還有一些 trick,可以參考 spanicker/main-thread-scheduling 裡的分析)


瀏覽器的 rIC 不適合的地方在哪兒呢,主要有兩點:

  • 本身不是用來處理重要的任務的,所以被調用次數不夠頻繁,即幀率達不到
  • 可能出現飢餓現象


基於此,我們就實現了我們的目標。而 React 把這叫做 Time Slicing。當然啦,順帶介紹的還有 Suspense。Suspense 又是什麼呢?

Suspense

https://twitter.com/acdlite/status/954798592320942081 這裡講了為什麼需要 Suspense 這樣的 API,還是那句話,用戶體驗。。。
- One reason iOS feels so much nicer than the web: fewer unnecessary loading states. Look what happens when you tap an option in the Settings app: rather than transition immediately and show a spinner, it pauses for a moment until the view is ready.
- The responses to my original tweet are correct. When waiting for something to load, it’s best to stay on the current view and wait until it’s ready. Only show the loading state as a fallback, after some threshold is crossed.

如何評價React的新功能Time Slice 和Suspense?​www.zhihu.com

展望 React 17,回顧 React 往事

展望 React 17,回顧 React 往事

嗯,這樣的 API 應該是為了和 react-loadable 兼容。(最終定型就是上面這樣,後面會講到)

同時, 這裡介紹了 suspense 的最初的想到的實現方式,後面被推翻了

以下兩段之前寫的,不寫也不好,源碼讀者歡迎交流:

如果使用了 Suspense,那麼 Suspense 的組件的 fiber 樹裡的更新很可能在不同的時間點執行,但是為了界面的不抖動,所以應該是把整棵樹一起 flush 到界面上。所以 React 弄了個 ReactFiberPendingPriority 模塊,目的就是讓 Suspense fiber 樹裡的所有 fiber 的 expirationTime 保持一致,從而能夠讓它們被同時 flush 到界面上。pending 是還未執行的意思。

為什麼 Suspense 的測試裡面要用 `await advanceTimers(xxms)`,因為內部的 rIc 實現本質還是依賴於 rAF,所以執行 Suspense 相關任務的時候是在 current tick 的末尾也就是 microtask 裡面執行的,所以要看效果也要到 current tick 的最末尾才看得到。而 `advanceTimers` 先執行 `jest.advanceTimersByTime()`, 然後返回一個 promise,自然就可以了。

Dan:

  • 目前的 React 生態裡的 code splitting 的方式會在「哪個組件去加載代碼或者數據」裡面耦合「在什麼地方顯示 spinner」的邏輯,Suspense 解決了這個問題(筆注:實現了解耦)。Placehoder 就像一個 `catch` ,會自動處理在它下方的依賴於它的異步的東西。(筆注:因為本質是 判斷 catch 到的是不是 Promise 從而進行處理)

筆注:這裡說的解耦個人理解是這樣的。以前我們做的 Spinner,如常見的上拉加載,我們需要把 `Spinner` 和 `List` 放在**同一個**組件中,如在加載組件`AutoLoadList` 中 `return this.data? <list> : <spinner>`。當然你把 Spinner 當成參數傳入也行,不過本質還是必須都在 `AutoLoadList` 這一個組件中。Suspense 解耦了這一操作,加載和 Spinner 是**分開的**,你可以在外層,甚至外層的外層套一個 `Placehoder`,而在最裡面的組件才進行加載數據(`resource.read(cache)`),兩者互無感知。/<spinner>/<list>

  • 還有比較重要的一點是,`Placehoder` 下面比如有 A, B(加載數據), C,D(加載數據) 四個組件,A 和 C 可以完全不受影響照常顯示以及和用戶進行交互(即便 B 和 D 已經是 spinner 了),這在以前是無法做到的。比如上面說的 `AutoLoadList` 組件,你用 `<autoloadlist>}>
    `,A 和 C 肯定是會受影響的。(當然你可以用比較 hack 的方式比如獲取實例然後看它是不是 intanceof 或者有其它的類似` `這種,都不說很..了,也會出現其它的限制,不可取)。
  • 這將我們從 code splitting 的摩擦中解放了出來。你不再需要手動地控制和擔心「那將會怎樣影響 app 裡能感知到的加載順序」。你可以 code split 一個葉子節點,它上方的現有的 Placehoder 會 catch 住它。


總結,Suspense 的重點在於:

  1. 在請求數據的時候,能夠不卸載之前的組件,即保持之前屏幕上的內容不變,同時可以交互(通過雙緩存來實現)
  2. 葉子節點能夠延遲某一整棵子樹的渲染,即可以實現讓視頻裡的電影海報 img 來延遲整個電影詳情頁的渲染的時機


說到這講個題外話:

在 React16 之前,React 是無法感知到跳出被處理的函數「範圍外」的 setState 的,比如你在某個 event handler 或者生命週期鉤子裡面執行 setTimeout,在 setTimeout 裡面進行 setState,這個時候的 setState 就是同步的了(即執行完 setState 之後 this.state 就已經是最新的了),這是因為這個 setTimeout 實際上不屬於 event handler 或者生命週期鉤子的一部分,無法通過像 `感知...; func(); 感知...` 這樣的流程被感知到,因為 `func()` 裡面包含了異步的 setTimeout。同步的流程自然無法感知到。

而到了 16 之後可以實現感知了。那是因為用了全局變量的關係。


好了,到這基本上 React 17 也就講得差不多了。前面說了 16 和 16.x 的很多 feature 都是為 17 服務的(特別是新聲明週期鉤子的改動),官方有博客這裡就不多說了。


下面基本是漫談了,我們先來看看 React 17 還有哪些 feature。

支持 Promise 組件

其實這只不過是稍微在 Suspense 的基礎上改了改,所以這個的 PR 改動的地方都不是很多。

<code><placeholder>






/<placeholder>

A:




/<code>

React 期望的是,當 PlaceHolder 的任意子節點有 Lazy 組件(組件是一個 Promise)的時候,初次渲染時不要把除了這些 lazy 的組件之外的其它部分的渲染到界面上,它們覺得這樣沒有意義,而且體驗不好(比如一個表格,內容是 lazy 的,你先把頭部展示出來也沒意義)。

React 希望的結果是,當這些 lazy 的組件 resolve 的時候,再一起展示整體,而關鍵的優化點在於,在初次渲染的時候,儘管需要等到 lazy 的組件 resolve 才能展示整體,它**能夠**開始渲染其它的組件,只是不把它們 commit(即渲染到界面上)。這樣實際上等到 lazy 的組件 resolve的時候,需要進行的工作就非常少了。

所以如果 resolve 的時間非常短,用戶根本就不會看到任何的 spinner,只有當 resolve 的時間超過某個值(有默認,你也可以自己設置),才會展示 spinner。

這樣就獲得了兩方面的優點,即讓 UI 交互更加流暢,也讓渲染性能能夠跟上。

而且這樣的設計,PlaceHolder 的位置可以非常靈活,你可以給整個 table 套上 PlaceHolder,也可以給某個單元格套上 PlaceHolder(這樣 spinner 只會出現在單元格中)。


總的來說,目前你無法做到兩件事,一是讓 PlaceHolder 能夠感知非常深的子組件裡面的 Promise(除非你用 redux 這種)。二是套在最外層的 PlaceHolder 無法繼續渲染那些不是 lazy 的子組件,只有當 lazy 的組件 resolve 的時候你才能去渲染,浪費了很多性能。

而且這種還可以搭配 Protal 用,組件的層級關係不再受影響,即之前沒有 Protal 的時候,DOM 裡面的 React root container 是無法感知到 Modal這種組件裡的狀態變化的

Render Props

最初的提出:`render` as a function of props and state · Issue #1387 · facebook/react

getDerivedStateFromCatch

Add stack unwinding phase for handling errors (#12201) · LeonYuAng3NT/react@a3f6936

與 cDC(componentDidCatch)的區別:https://www.reddit.com/r/reactjs/comments/9lp0k3/new_lifecycle_method_getderivedstatefromerror/e79elpl/?utm_source=reddit-android

Support lazy component

即前面 Suspense 裡提到的 LazyloadComponent 。

注意兩點,一是 Suspense 裡就提到的,不要立即顯示 spinner。二是複用 fetch data 裡的 spinner(放在共同的的父級組件裡就行了嘛)。


各種對 explicit 的詮釋

  • Fiber 本身:一個 fiber 只需要在自己的數據結構上聲明一下 expriationTime 就行,不需要自己去管我該什麼時候去插入,更新。而是完全由 schedule 來控制
  • 為什麼不引入 keep-alive:can React support feature like keep-alive in Vue?


嗯,說了這麼多,總的來總結一下 React 17:

展望 React 17,回顧 React 往事

https://www.reddit.com/r/reactjs/comments/9ksj2l/acdlites_react_roadmap_presentedframework_summit

「非前端技術」

  • Double buffering
  • polling object:
展望 React 17,回顧 React 往事

  • unwinding stack
  • continuations and CPS (嗯...這個很早就提到過了,很多非常多次,最早在看 SICP 的時候就聽到過了,一直沒有搞懂,這是我看過的最好的文章)
  • Bitwise operator(用了 fiber 的 effectTag):Bitwise operators

- `if(tag & ...)`:判斷是否有某個 tag

- `tag |= ...`:加上某個 tag

- `tag |= ~(...)`:去掉某個 tag

- `tag ^= ...`:toogle 某個 tag(有就去掉,沒有就加上)

  • copy-on-write
  • 當然代碼或者 v8 相關的優化就比較多了,hidden class,hot path,還有好多想不起來也不知道叫啥名字的。。
  • 可重入性:
展望 React 17,回顧 React 往事


FAQ

為什麼要提出 Expiration Time,並廢棄 ReactPriorityLevel 模塊(注意沒有廢棄 priority 這個概念)?

答:在處理飢餓問題時,如果採用優先級算法,那麼需要人為的去調整優先級(增加或減少),而用當前的時間與 expirationTime 的差值來代表優先級的話,就不用去認為解決飢餓問題了,因為時間自己就是流逝的,差值肯定會越來越小,優先級自然會自動增加,也就不會存在飢餓現象了


為什麼去除對原生 requestIdleCallback 的依賴?(好像前面已經提到過了)

  • 因為瀏覽器對調度回調不敏感
  • 個人感覺另外的原因是支持太差


為什麼不用 generator 去實現 yield,而用了其它的實現?

  • 最初的思想基於 generator,但是源碼中卻完全沒用用到過 generator,而是用了自己的一套方案去實現 generator。(其實一開始是用的,Seb 在演講的時候提到過,後面去掉了),參考 Seb 的 comment)


React 的理念在於:

展望 React 17,回顧 React 往事

Sebastian god

展望 React 17,回顧 React 往事

Sebastian god

展望 React 17,回顧 React 往事

https://twitter.com/acdlite/status/1047187257852145664

其它未來

seb 最近把重心都放在了OCaml 和 prepack 上,後面應該是有大招的(猜測。。)

結語

寫這個文章主要是因為從種種跡象來看,再過 20 天的 React conf 他們應該就要放大招了,到時候再寫感覺積極性就失去了很多。


React 即是冰山,也是冰山的入口,打開之後有太多的東西能夠學習和探索,很多時候看一個 issue,PR,tweet,都能感受到自己知識的侷限和渺小。React 裡面的很多東西和思想,包括變量名,函數名,甚至註釋,都來自於其它語言,方向。而 React 本身也回饋給了開源社區,如 display-lock,immutable.js proposal,rIC 加強 Priority Queue Option · Issue #68 · w3c/requestidlecallback ,不依賴框架的 Scheduler 等等。


最後,希望能夠拋磚引玉,在不久的將來能看到《React 編年史》之類的東西那就太高興了(國外有一個類似的,但是太少了,三四百字符,自己也嘗試過,確實水平和精力不夠)。必須要承認,筆者自己是 15.0 之後才剛剛開始接觸 React 的,所以對歷史甚至是 15.0 的瞭解也不夠深入,表現在沒有系統的深入的瞭解過(除開官方文檔的所有內容以及部分 gh,twitter,blog 的資料),即沒有閱讀過《深入 React 技術棧》類似這樣的書籍,也沒有閱讀過 15 的源碼等等。如有錯誤,還望大家批評糾正


分享到:


相關文章: