悄悄的, React v16.7 發佈了。 React v16.7: No, This Is Not The One With Hooks.
javascript
最近我也一直在關注這兩個功能,就花些時間就整理了一下資料, 在此分享給你們, 但願對你們有所幫助。html
爲何不推薦在 componentwillmount 裏最獲取數據的操做呢?
前端
這個問題被過問不少遍了, 前幾天又討論到這個問題, 就以這個做爲切入點吧。java
有些朋友可能會想, 數據早點獲取回來,頁面就能快點渲染出來呀, 提高用戶體驗, 何樂而爲不爲?
react
這個問題, 簡單回答起來就是, 由於是可能會調用屢次
。 webpack
要深刻回答這個問題, 就不得不提到一個React 的核心概念: React Fiber
.web
React Fiber 是在 v16 的時候引入的一個全新架構, 旨在解決異步渲染
問題。ajax
新的架構使得使得 React 用異步渲染成爲可能,但要注意,這個改變只是讓異步渲染成爲可能
。編程
可是React 卻並無在 v16 發佈的時候馬上開啓,也就是說,React 在 v16 發佈以後依然使用的是同步渲染
。api
不過,雖然異步渲染沒有馬上採用,Fiber 架構仍是打開了通向新世界的大門,React v16 一系列新功能幾乎都是基於 Fiber 架構。
說到這, 也要說一下 同步渲染
和 異步渲染
.
咱們都知道React 是facebook 推出的, 他們內部也在大量使用這個框架,(我的感受是很良心了, 內部推進, 而不是丟出去拿用戶當小白鼠), 而後就發現了不少問題, 比較突出的就是渲染問題
。
他們的應用是比較複雜的, 組件樹也是很是龐大, 假設有一千個組件要渲染, 每一個耗費1ms, 一千個就是1000ms, 因爲javascript 是單線程的, 這 1000ms 裏 CPU 都在努力的幹活, 一旦開始,中間就不會停。 若是這時候用戶去操做, 好比輸入, 點擊按鈕, 此時頁面是沒有響應的。 等更新完了, 你以前的那些輸入就會啪啪啪一會兒出來了。
這就是咱們說的頁面卡頓
, 用起來很不爽, 體驗很差。
這個問題和設備性能沒有多大關係, 歸根結底仍是同步渲染機制
的問題。
目前的React 版本(v16.7), 當組件樹很大的時候,也會出現這個問題, 逐層渲染, 逐漸深刻,不更新完就不會停
。
函數調用棧如圖所示:
由於JavaScript單線程的特色,每一個同步任務不能耗時太長,否則就會讓程序不會對其餘輸入做出相應,React的更新過程就是犯了這個禁忌,而React Fiber就是要改變現狀。
Fiber 的作法是:分片。
把一個很耗時的任務分紅不少小片,每個小片的運行時間很短,雖然總時間依然很長,可是在每一個小片執行完以後,都給其餘任務一個執行的機會,這樣惟一的線程就不會被獨佔
,其餘任務依然有運行的機會。 而維護每個分片的數據結構, 就是Fiber
。
用一張圖來展現Fiber 的碎片化更新過程:
中間每個波谷表明深刻某個分片的執行過程,每一個波峯就是一個分片執行結束交還控制權的時機。
更詳細的信息能夠看: Lin Clark - A Cartoon Intro to Fiber - React Conf 2017
在React Fiber中,一次更新過程會分紅多個分片完成,因此徹底有可能一個更新任務尚未完成,就被另外一個更高優先級的更新過程打斷
,這時候,優先級高的更新任務會優先處理完,而低優先級更新任務所作的工做則會徹底做廢,而後等待機會重頭再來
。
由於一個更新過程可能被打斷,因此React Fiber一個更新過程被分爲兩個階段: render phase
and commit phase
.
render phase
and commit phase
有了Fiber 以後, react 的渲染過程再也不是一旦開始就不能終止的模式了, 而是劃分紅爲了兩個過程: 第一階段和第二階段, 也就是官網所謂的 render phase
and commit phase
。
在 Render phase 中, React Fiber會找出須要更新哪些DOM,這個階段是能夠被打斷的, 而到了第二階段commit phase, 就一氣呵成把DOM更新完,毫不會被打斷。
這兩個階段, 分界點
是什麼呢?
實際上是 render 函數
。 並且, render 函數 也是屬於 第一階段 render phase 的
。
那這兩個 phase 包含的的生命週期函數有哪些呢?
render phase
:
commit phase
:
由於第一階段的過程會被打斷並且「重頭再來」,就會形成意想不到的狀況。
好比說,一個低優先級的任務A正在執行,已經調用了某個組件的componentWillUpdate函數,接下來發現本身的時間分片已經用完了,因而冒出水面,看看有沒有緊急任務,哎呀,真的有一個緊急任務B,接下來React Fiber就會去執行這個緊急任務B,任務A雖然進行了一半,可是沒辦法,只能徹底放棄,等到任務B全搞定以後,任務A重頭來一遍,注意,是重頭來一遍,不是從剛纔中段的部分開始,也就是說,componentWillUpdate函數會被再調用一次。
在現有的React中,每一個生命週期函數在一個加載或者更新過程當中絕對只會被調用一次;在React Fiber中,再也不是這樣了,第一階段中的生命週期函數在一次加載和更新過程當中可能會被屢次調用!
。
這裏也能夠回答文行開頭的那個問題了, 固然, 在異步渲染模式沒有開啓以前, 你能夠在 willMount 裏作ajax (不建議)。 首先,一個組件的 componentWillMount 比 componentDidMount 也早調用不了幾微秒,性能沒啥提升,並且若是開啓了異步渲染, 這就難受了。 React 官方也意識到了這個問題,以爲有必要去勸告(威脅, 阻止)開發者不要在render phase 裏寫有反作用
的代碼了(反作用:簡單說就是作本函數以外的事情,好比改一個全局變量, ajax之類)。
static getDerivedStateFromProps(nextProps, prevState) { //根據nextProps和prevState計算出預期的狀態改變,返回結果會被送給setState }
爲了減小(避免?)一些開發者的騷操做,React v16.3,乾脆引入了一個新的生命週期函數 getDerivedStateFromProps
, 這個函數是一個 static 函數,也是一個純函數
,裏面不能經過 this 訪問到當前組件
(強制避免一些有反作用的操做),輸入只能經過參數,對組件渲染的影響只能經過返回值。目的大概也是讓開發者逐步去適應異步渲染。
咱們再看一下 React v16.3 以前的的生命週期函數 示意圖:
再看看16.3的示意圖:
上圖中幷包含所有React生命週期函數,另外在React v16發佈時,還增長了一個componentDidCatch
,當異常發生時,一個能夠捕捉到異常的componentDidCatch
就排上用場了。不過,很快React覺着這還不夠,在v16.6.0又推出了一個新的捕捉異常的生命週期函數getDerivedStateFromError
。
若是異常發生在render階段
,React就會調用getDerivedStateFromError
,若是異常發生在第commit階段
,React會調用componentDidCatch
。 這個異常能夠是任何類型的異常, 捕捉到這個異常以後呢, 能夠作一些補救之類的事情。
componentDidCatch
和 getDerivedStateFromError
的 區別componentDidCatch 和 getDerivedStateFromError 都是能捕捉異常的,那他們有什麼區別呢?
咱們以前說了兩個階段, render phase
和 commit phase
.
render phase 裏產生異常的時候, 會調用 getDerivedStateFromError
;
在 commit phase 裏產生異常大的時候, 會調用 componentDidCatch
。
嚴格來講, 其實還有一點區別:
componentDidCatch 是不會在服務器端渲染
的時候被調用的 而 getDerivedStateFromError 會。
囉裏八嗦一大堆, 關於背景的東西就說到這, 你們只須要了解什麼是Fiber: ‘ 哦, 這個這個東西是支持異步渲染的, 雖然這個東西還沒開啓’。
而後就是渲染的兩個階段:renderphase
和 commit phase
.
能夠被打斷
, 你們不要在此階段作一些有反作用
的操做,能夠放心在commit phase
裏作。如今咱們進入正題: Suspense
和 Hooks
。
Suspense要解決的兩個問題:
剛開始的時候, React 以爲本身只是管視圖的, 代碼打包的事不歸我管, 怎麼拿數據也不歸我管。 代碼都打到一塊兒, 好比十幾M, 下載就要半天,體驗顯然不會好到哪裏去。
但是後來呢,這兩個事情愈來愈重要, React 又以爲, 嗯,仍是要摻和一下,是時候站出來展示真正的技術了。
Suspense 在v16.6的時候 已經解決了代碼分片的問題,異步獲取數據尚未正式發佈。
先看一個簡單的例子:
import React from "react"; import moment from "moment"; const Clock = () => <h1>{moment().format("MMMM Do YYYY, h:mm:ss a")}</h1>; export default Clock;
假設咱們有一個組件, 是看當前時間的, 它用了一個很大的第三方插件, 而我想只在用的時候再加載資源,不打在總包裏。
再看一段代碼:
// Usage of Clock const Clock = React.lazy(() => { console.log("start importing Clock"); return import("./Clock"); });
這裏咱們使用了React.lazy, 這樣就能實現代碼的懶加載。 React.lazy 的參數是一個function, 返回的是一個promise. 這裏返回的是一個import 函數, webpack build 的時候, 看到這個東西, 就知道這是個分界點。 import 裏面的東西能夠打包到另一個包裏。
真正要用的話, 代碼大概是這個樣子的:
<Suspense fallback={<Loading />}> { showClock ? <Clock/> : null} </Suspense>
showClock 爲 true, 就嘗試render clock, 這時候, 就觸發另外一個事件: 去加載clock.js 和它裏面的 lib momment。
看到這你可能以爲奇怪, 怎麼還須要用個<Suspense> 包起來, 有啥用, 不包行不行。
哎嗨, 不包還真是不行。 爲何呢?
前面咱們說到, 目前react 的渲染模式仍是同步的, 一口氣走到黑, 那我如今畫到clock 這裏, 可是這clock 在另一個文件裏, 服務器就須要去下載, 何時能下載完呢, 不知道。 假設你要花十分鐘去下載, 那這十分鐘你讓react 去幹啥, 總不能一直等你吧。 Suspens 就是來解決這個問題的, 你要畫clock, 如今沒有,那就會拋一個異常出來,咱們以前說
componentDidCatch 和 getDerivedStateFromProps, 這兩個函數就是來抓子組件 或者 子子組件拋出的異常的。
子組件有異常的時候就會往上拋,直到某個組件的 getDerivedStateFromProps 抓住這個異常,抓住以後幹嗎呢, 還能幹嗎呀, 忍着。 下載資源的時候會拋出一個promise, 會有地方(這裏是suspense)捕捉這個promise, suspense 實現了getDerivedStateFromProps, getDerivedStateFromProps 捕獲到異常的時候, 一看, 哎, 小老弟,你來啦,仍是個promise, 而後就等這個promise resole, resolve 完成以後呢,它會嘗試從新畫一會兒組件。這時候資源已經到本地了, 也就能畫成功了。
用僞代碼 大體實現一下:
getDerivedStateFromError(error) { if (isPromise(error)) { error.then(reRender); } }
以上大概就是Suspense 的原理, 其實也不是很複雜,就是利用了 componentDidCatch 和 getDerivedStateFromError, 其實剛開始在v16的時候, 是要用componentDidCatch 的, 但它畢竟是commit phase 裏的東西, 仍是分出來吧, 因此又加了個getDerivedStateFromError來實現 Suspense 的功能。
這裏須要注意的是 reRender 會渲染suspense 下面的全部子組件。
異步渲染何時開啓呢, 根據介紹說是在19年的第二個季度隨着一個小版本的升級開啓, 讓咱們提早作好準備。
作些什麼準備呢?
到這, 咱們說完了Suspense 的一半功能, 還有另外一半: 異步獲取數據。
目前這一部分功能還沒正式發佈。 那咱們獲取數據仍是隻能在commit phase 作, 也就是在componentDidMount 裏 或者 didUpdate 裏作。
就目前來講, 若是一個組件要本身獲取數據, 就必須實現爲一個類組件, 並且會畫兩次, 第一次沒有數據, 是空的, 你能夠畫個loading, didMount 以後發請求, 數據回來以後, 把數據setState 到組件裏, 這時候有數據了, 再畫一次,就畫出來了。
雖然是一個很簡答的功能, 我就想請求個數據, 還要寫一堆東西, 很麻煩, 但在目前的正式版裏, 不得不這麼作。
但之後這種狀況會獲得改善, 看一段示例:
import {unstable_createResource as createResource} from 'react-cache'; const resource = createResource(fetchDataApi); const Foo = () => { const result = resource.read(); return ( <div>{result}</div> ); // ... <Suspense> <Foo /> </Suskpense>};
代碼裏咱們看不到任何譬如 async await 之類的操做, 看起來徹底是同步的操做, 這是什麼原理呢。
上面的例子裏, 有個 resource.read()
, 這裏就會調api, 返回一個promise, 上面會有suspense 抓住, 等resolve 的時候,再畫一下, 就達到目的了。
到這,細心的同窗可能就發現了一個問題, resource.read(); 明顯是一個有反作用的操做, 並且 render 函數又屬於render phase, 以前又說, 不建議在 render phase 裏作有反作用的操做, 這麼矛盾, 不是本身打臉了嗎。
這裏也能看出來React 團隊如今還沒徹底想好, 目前放出來測試api 也是以unstable_
開頭的, 不用用意仍是跟明顯的: 讓你們不要寫class的組件
,Suspense 能很好的支持函數式組件。
React v16.7.0-alpha 中第一次引入了 Hooks 的概念, 爲何要引入這個東西呢?
有兩個緣由:
最終目的就是, 開發者不用去理解class, 也不用操心生命週期方法。
可是React 官方又說, Hooks的目的並非消滅類組件。此處應手動滑稽。
迴歸正題, 咱們繼續看Hooks, 首先看一下官方的API:
乍一看仍是挺多的, 其實有不少的Hook 還處在實驗階段,極可能有一部分要被砍掉, 目前你們只須要熟悉的, 三個就夠了:
舉個例子來看下, 一個簡單的counter :
// 有狀態類組件 class Counter extends React.Component { state = { count: 0 } increment = () => { this.setState({count: this.state.count + 1}); } minus = () => { this.setState({count: this.state.count - 1}); } render() { return ( <div> <h1>{this.state.count}</h1> <button onClick={this.increment}>+</button> <button onClick={this.minus}>-</button> </div> ); } }
// 使用useState Hook const Counter = () => { const [count, setCount] = useState(0); const increment = () => setCount(count + 1); return ( <div> <h1>{count}</h1> <button onClick={increment}>+</button> </div> ); };
這裏的Counter 不是一個類了, 而是一個函數。
進去就調用了useState, 傳入 0,對state 進行初始化,此時count 就是0, 返回一個數組, 第一個元素就是 state 的值,第二個元素是更新 state 的函數。
// 下面代碼等同於: const [count, setCount] = useState(0); const result = useState(0); const count = result[0]; const setCount = result[1];
利用 count 能夠讀取到這個 state,利用 setCount 能夠更新這個 state,並且咱們徹底能夠控制這兩個變量的命名,只要高興,你徹底能夠這麼寫:
const [theCount, updateCount] = useState(0);
由於 useState 在 Counter 這個函數體中,每次 Counter 被渲染的時候,這個 useState 調用都會被執行,useState 本身確定不是一個純函數,由於它要區分第一次調用(組件被 mount 時)和後續調用(重複渲染時),只有第一次才用得上參數的初始值,然後續的調用就返回「記住」的 state 值。
讀者看到這裏,內心可能會有這樣的疑問:若是組件中屢次使用 useState 怎麼辦?React 如何「記住」哪一個狀態對應哪一個變量?
React 是徹底根據 useState 的調用順序
來「記住」狀態歸屬的,假設組件代碼以下:
const Counter = () => { const [count, setCount] = useState(0); const [foo, updateFoo] = useState('foo'); // ... }
每一次 Counter 被渲染,都是第一次 useState 調用得到 count 和 setCount,第二次 useState 調用得到 foo 和 updateFoo(這裏我故意讓命名不用 set 前綴,可見函數名能夠隨意)。
React 是渲染過程當中的「上帝」,每一次渲染 Counter 都要由 React 發起,因此它有機會準備好一個內存記錄
,當開始執行的時候,每一次 useState 調用對應內存記錄上一個位置
,並且是按照順序來記錄的
。React 不知道你把 useState 等 Hooks API 返回的結果賦值給什麼變量,可是它也不須要知道,它只須要按照 useState 調用順序記錄就行了。
你能夠理解爲會有一個槽去記錄狀態。
正由於這個緣由,Hooks,千萬不要在 if 語句或者 for 循環語句中使用!
像下面的代碼,確定會出亂子的:
const Counter = () => { const [count, setCount] = useState(0); if (count % 2 === 0) { const [foo, updateFoo] = useState('foo'); } const [bar, updateBar] = useState('bar'); // ... }
由於條件判斷,讓每次渲染中 useState 的調用次序不一致了,因而 React 就錯亂了。
除了 useState,React 還提供 useEffect,用於支持組件中增長反作用的支持。
在 React 組件生命週期中若是要作有反作用的操做,代碼放在哪裏?
固然是放在 componentDidMount 或者 componentDidUpdate 裏,可是這意味着組件必須是一個 class。
在 Counter 組件,若是咱們想要在用戶點擊「+」或者「-」按鈕以後把計數值體如今網頁標題上,這就是一個修改 DOM 的反作用操做,因此必須把 Counter 寫成 class,並且添加下面的代碼:
componentDidMount() { document.title = `Count: ${this.state.count}`; } componentDidUpdate() { document.title = `Count: ${this.state.count}`; }
而有了 useEffect,咱們就不用寫一個 class 了,對應代碼以下:
import { useState, useEffect } from 'react'; const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { document.title = `Count: ${this.state.count}`; }); return ( <div> <div>{count}</div> <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div> ); };
useEffect 的參數是一個函數,組件每次渲染以後,都會調用這個函數參數,這樣就達到了 componentDidMount 和 componentDidUpdate 同樣的效果。
雖然本質上,依然是 componentDidMount
和 componentDidUpdate
兩個生命週期被調用,可是如今咱們關心的不是 mount 或者 update 過程,而是「after render」事件,useEffect 就是告訴組件在「渲染完」以後作點什麼事。
讀者可能會問,如今把 componentDidMount
和 componentDidUpdate
混在了一塊兒,那假如某個場景下我只在 mount 時作事但 update
不作事,用 useEffect
不就不行了嗎?
其實,用一點小技巧就能夠解決。useEffect
還支持第二個可選參數
,只有同一 useEffect 的兩次調用第二個參數不一樣時,第一個函數參數纔會被調用. 因此,若是想模擬 componentDidMount,只須要這樣寫:
useEffect(() => { // 這裏只有mount時才被調用,至關於componentDidMount }, [123]);
在上面的代碼中,useEffect 的第二個參數是 [123],其實也能夠是任何一個常數,由於它永遠不變,因此 useEffect 只在 mount 時調用第一個函數參數一次,達到了 componentDidMount 同樣的效果。
在前面介紹「提供者模式」章節咱們介紹過 React 新的 Context API,這個 API 不是完美的,在多個 Context 嵌套
的時候尤爲麻煩。
好比,一段 JSX 若是既依賴於 ThemeContext 又依賴於 LanguageContext,那麼按照 React Context API 應該這麼寫:
<ThemeContext.Consumer> { theme => ( <LanguageContext.Cosumer> language => { //可使用theme和lanugage了 } </LanguageContext.Cosumer> ) } </ThemeContext.Consumer>
由於 Context API 要用 render props,因此用兩個 Context 就要用兩次 render props,也就用了兩個函數嵌套,這樣的縮格看起來也的確過度了一點點。
使用 Hooks 的 useContext,上面的代碼能夠縮略爲下面這樣:
const theme = useContext(ThemeContext); const language = useContext(LanguageContext); // 這裏就能夠用theme和language了
這個useContext把一個須要很費勁才能理解的 Context API 使用大大簡化,不須要理解render props,直接一個函數調用就搞定。
可是,useContext也並非完美的,它會形成意想不到的從新渲染,咱們看一個完整的使用useContext的組件。
const ThemedPage = () => { const theme = useContext(ThemeContext); return ( <div> <Header color={theme.color} /> <Content color={theme.color}/> <Footer color={theme.color}/> </div> ); };
由於這個組件ThemedPage使用了useContext
,它很天然成爲了Context的一個消費者
,因此,只要Context的值發生了變化,ThemedPage就會被從新渲染
,這很天然,由於不從新渲染也就沒辦法從新得到theme值,但如今有一個大問題,對於ThemedPage來講,實際上只依賴於theme中的color屬性,若是隻是theme中的size發生了變化可是color屬性沒有變化,ThemedPage依然會被從新渲染,固然,咱們經過給Header、Content和Footer這些組件添加shouldComponentUpdate實現能夠減小沒有必要的從新渲染,可是上一層的ThemedPage中的JSX從新渲染是躲不過去了。
說到底,useContext
須要一種表達方式告訴React:「我沒有改變,重用上次內容好了。」
但願Hooks正式發佈的時候可以彌補這一缺陷。
上面咱們介紹了 useState
、useEffect
和 useContext
三個最基本的 Hooks,能夠感覺到,Hooks 將大大簡化使用 React 的代碼。
首先咱們可能再也不須要 class了,雖然 React 官方表示 class 類型的組件將繼續支持,可是,業界已經廣泛表示會遷移到 Hooks 寫法上,也就是放棄 class,只用函數形式來編寫組件。
對於 useContext,它並無爲消除 class 作貢獻,卻爲消除 render props 模式作了貢獻。很長一段時間,高階組件和 render props 是組件之間共享邏輯的兩個武器,但如同我前面章節介紹的那樣,這兩個武器都不是十全十美的,如今 Hooks 的出現,也預示着高階組件和 render props 可能要被逐步取代。
但讀者朋友,不要以爲以前學習高階組件和 render props 是浪費時間,相反,你只有明白 React 的使用歷史,才能更好地理解 Hooks 的意義。
能夠預測,在 Hooks 興起以後,共享代碼之間邏輯會用函數形式,並且這些函數會以 use-
前綴爲約定,重用這些邏輯的方式,就是在函數形式組件中調用這些 useXXX 函數。
例如,咱們能夠寫這樣一個共享 Hook useMountLog,用於在 mount 時記錄一個日誌,代碼以下:
const useMountLog = (name) => { useEffect(() => { console.log(`${name} mounted`); }, [123]); }
任何一個函數形式組件均可以直接調用這個 useMountLog 得到這個功能,以下:
const Counter = () => { useMountLog('Counter'); ... }
對了,全部的 Hooks API 都只能在函數類型組件中調用,class 類型的組件不能用,從這點看,很顯然,class 類型組件將會走向消亡。
Hooks 將來正式發佈後, 咱們天然而然的會遇到這個問題, 如何把寫在舊生命週期內的邏輯遷移到Hooks裏面來。下面咱們就簡單說一下,
useMemo(() => { // execute only once }, []);
咱們能夠看到useMemo 接收兩個參數, 第一個參數是一個函數, 第二個參數是一個數組。
這裏有個地方要注意, 就是, 第二個參數的數組裏的元素和上一次執行useMemo的第二個參數的數組的元素 徹底同樣的話,那就表示沒有變化, 就不用執行第一個參數裏的函數了。 若是有不一樣, 說明有變化, 就執行。
上面的例子裏, 咱們只傳入了一個空數組, 不會有變化, 也就是隻會執行一次。
const areEqual = (prevProps, nextProps) => { // 返回結果和shouldComponentUpdate正好相反 // 訪問不了state }; React.memo(Foo, areEqual);
useEffect(() => { // 這裏在mount時執行一次 }, []);
const mounted = useRef(); useEffect(() => { if (!mounted.current) { mounted.current = true; } else { // 這裏只在update是執行 } });
useEffect(() => { // 這裏在mount時執行一次 return () => { // 這裏在unmount時執行一次 } }, []);
Hooks 將來發布以後, 咱們的代碼會寫成什麼樣子呢? 簡單設想一下:
// Hooks以後的組件邏輯重用形態 const XXXX = () => { const [xx, xxx, xxxx] = useX(); useY(); const {a, b} = useZ(); return ( <> //JSX </> ); };
內部可能用各類Hooks, 也可能包含第三方的Hooks。 分享Hooks 就是實現代碼重用的一種形勢。 其實如今已經有人在作這方面的工做了: useHooks.com, 有興趣的朋友能夠去看下。
Suspense 和 Hooks 發佈後, 會帶來什麼樣的改變呢? 毫無疑問, 將來的組件, 更多的將會是函數式組件。
緣由很簡單, 之後你們分享出來的都是Hooks,這東西只能在函數組件裏用啊, 其餘地方用不了,後面就會天然而然的發生了。
但函數式組件和函數式編程還不是同一個概念。 函數式編程必須是純的, 沒有反作用的, 函數式組件裏, 不能保證, 好比那個resource.read(), 明顯是有反作用的。
既然這兩個東西是趨勢, 那這兩個東西到底好很差呢 ?
我的理解, 任何東西都不是十全十美。 既然大勢所趨, 咱們就努力去了解它,學會它, 努力用它好的地方, 避免用很差的地方。
最新的消息: https://reactjs.org/blog/2018...
明顯可以看到資源在往 Suspense 和 Hooks 傾斜。
看到這, 相信你們都Suspense 和 Hooks 都有了一個大概的瞭解了。
收集各類資料花費了挺長時間,大概用了兩三天寫出來,中間參考了不少資料, 一部分是摘錄到了上面的內容裏。
在這裏整理分享一下, 但願對你們有所幫助。
才疏學淺, 不免會有紕漏, 歡迎指正:)。
以爲內容有幫助能夠關注下個人公衆號 「 前端e進階 」,一塊兒學習成長