摘要:來個使用類形式的例子以上就不說解釋了,第一篇已經講過了,接著將改成用的形式接著使用形式接收一個對象的返回值并返回該的當前值。如果的返回值是函數的話,那么就可以簡寫成的方式,只是簡寫而已,實際并沒有區別。
本文是 React 系列的第三篇
React 新特性講解及實例(一)
React 新特性 Hooks 講解及實例(二)
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你!
使用 Context Hooks使用 Context ,首先頂層先聲明 Provier 組件,并聲明 value 屬性,接著在后代組件中聲明 Consumer 組件,這個 Consumer 子組件,只能是唯一的一個函數,函數參數即是 Context 的負載。如果有多個 Context ,Provider 和 Consumer 任意的順序嵌套即可。
此外我們還可以針對任意一個 Context 使用 contextType 來簡化對這個 Context 負載的獲取。但在一個組件中,即使消費多個 Context,contextType 也只能指向其中一個
在 Hooks 環境中,依舊可以使用 Consumer,但是 ContextType 作為類靜態成員肯定是用不了。Hooks 提供了 useContext,不但解決了 Consumer 難用的問題同時也解決了 contextType 只能使用一個 context 的問題。
來個使用類形式的例子:
class Foo extends Component { render() { return ({ count => ) } } function App (props) { const [count, setCount] = useState(0); return ({count}
}) }
以上就不說解釋了,第一篇已經講過了,接著將 Foo 改成用 contextType 的形式:
class Foo extends Component { static contextType = CountContext; render() { const count = this.context return ({count}
) } }
接著使用 useContext 形式:
function Foo () { const count = useContext(CountContext) return ({count}
) }
useContext 接收一個 context 對象(React.createContext 的返回值)并返回該 context 的當前值。當前的 context 值由上層組件中距離當前組件最近的
當組件上層最近的
別忘記 useContext 的參數必須是 context 對象本身:
正確: useContext(MyContext)
錯誤: useContext(MyContext.Consumer)
錯誤: useContext(MyContext.Provider)
調用了 useContext 的組件總會在 context 值變化時重新渲染。如果重渲染組件的開銷較大,你可以 通過使用 memoization 來優化。
使用 Memo Hooksmeno 用來優化函數組件重渲染的行為,當傳入屬性值都不變的情況下,就不會觸發組件的重渲染,否則就會觸發組件重渲染。
useMemo 與 memomeno針對的是一個組件的渲染是否重復執行,而 useMemo 定義的是一個函數邏輯是否重復執行。
來個粟子:
function Foo (props) { return ({props.count}
) } function App (props) { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count]) return () }
運行結果:
如上所示,useMemo 語法與 useEffect 是一致的。第一個參數是需要執行的邏輯函數,第二個參數是這個邏輯依賴輸入變量組成的數組,如果不傳第二個參數,這 useMemo 的邏輯每次就會運行,useMemo 本身的意義就不存在了,所以需要傳入參數。所以傳入空數組就只會運行一次,策略與 useEffect 是一樣的,但有一點比較大的差異就是調用時機,useEffect 執行的是副作用,所以一定是渲染之后才執行,但 useMemo 是需要返回值的,而返回值可以直接參與渲染,因此 useMemo 是在渲染期間完成的。
接下來改造一下 useMemo,讓它依賴 count 如下:
const double = useMemo(() => { return count * 2 }, [count])
接著只有當 count 變化時,useMemo 才會執行。
再次修改 useMemo, 如下:
const double = useMemo(() => { return count * 2 }, [count === 3])
現在能斷定,count 在等于 3 之前,由于這個條件一直保存 false 不變,double 不會重新計算,所以一直是 0,當 count 等于 3,double 重新計算為 6,當 count 大于 3,double 在重新計算,變成 8,然后就一直保存 8 不變。
記住,傳入的 useMemo 的函數會在渲染期間執行,請不要在這個函數內部執行與渲染無關的聽任,諸如副作用這類操作屬于 useEffect 的適用范疇,而不是 useMemo。
你可以把 useMemo 作為性能優化的手段,但不要把它當成語義上的保證。
使用 useCallback Hooks接下先看一下使用 memo 優化子組件的例子。
const Foo = memo (function Foo (props) { console.log("Counter render") return ({props.count}
) }) function App (props) { const [count, setCount] = useState(0); const double = useMemo(() => { return count * 2 }, [count === 3]) return () }
使用 memo 包裹 Foo 組件,這樣只有當 double 變化時,Foo 組件才會重新渲染,執行里面的 log,運行結果如下:
現在在給 Foo 中的 h1 添加一個 click 事件:
const Foo = memo (function Foo (props) { console.log("Counter render") return ({props.count}
) })
然后在 App 組件中聲明 onClick 并傳給 Foo 組件:
function App (props) { ... const onClick = () => { console.log("Click") } return (...) }
看下運行效果:
可以看出,每次點擊,不管 double 是否有變化, Foo 組件都會被渲染。那就說明每次 App 重新渲染之后, onClick 句柄的變化,導致 Foo 也被連帶重新渲染了。count 經常變化可以理解,但是 onClick 就不應該經常變化了,畢竟只是一個函數而已,所以我們要想辦法讓 onClick 句柄不變化。
想想我們上面講的 useMemo,可以這樣來優化 onClick:
const onClick = useMemo(() => { return () => { console.log("Click") } }, [])
由于我們傳給 useMemo 的第二個參數是一個空數組,那么整個邏輯就只會運行一次,理論上我們返回的 onClick 就只有一個句柄。
運行效果:
現在我們把 useCallback 來實現上頁 useMemo 的邏輯。
const onClick = useCallback(() => { console.log("Click") },[])
如果 useMemo 返回的是一個函數,那么可以直接使用 useCallback 來省略頂層的函數。
useCallback(fn, deps) 相當于 useMemo(() => fn, deps)
大家可能有一個疑問,useCallback 這幾行代碼明明每次組件渲染都會創建新的函數,它怎么就優化性能了呢。
注意,大家不要誤會,使用 useCallback 確實不能阻止創建新的函數,但這個函數不一定會被返回,也就是說這個新創建的函數可能會被拋棄。useCallback解決的是解決的傳入子組件的函數參數過多變化,導致子組件過多渲染的問題,這里需要理解好。
上述我們第二個參數傳入的空數組,在實際業務并沒有這么簡單,至少也要更新一下狀態。舉個粟子:
function App (props) { ... const [clickCount, setClickCount] = useState(0); const onClick = useCallback(() => { console.log("Click") setClickCount(clickCount + 1) },[clickCount, setClickCount]) ... }
在 APP 組件中在聲明一個 useState,然后在 onClick 中調用 setClickCount,此時 onClick 依賴 clickCount,setClickCount。
其實這里的 setClickCount 是不需要寫的,因為 React 能保證 setState 每次返回的都是同個句柄。不信,可以看下官方文檔 :
這里的場景,除了直接使用 setClickCount + 1 賦值以外, 還有一種方式甚至連 clickCount都不用依賴。setState 除了傳入對應的 state 最新值以外,還可以傳入一個函數,函數的參數即這個 state 的當前值,返回就是要更新的值:
const onClick = useCallback(() => { console.log("Click") setClickCount((clickCount) => clickCount + 1) },[])小結
和 memo 根據屬性來決定是否重新渲染組件一樣,useMemo 可以根據指定的依賴不決定一段函數邏輯是否重新執行,從而優化性能。
如果 useMemo 的返回值是函數的話,那么就可以簡寫成 useCallback 的方式,只是簡寫而已,實際并沒有區別。
需要特別注意的是,當依賴變化時,我們能斷定 useMemo 一定重新執行。但是,即使依賴不變化我們不能假定它就一定不會重新執行,也就是說,它可以會執行,就是考慮內在優化結果。
我們可以把 useMemo, useCallback 當做一個錦上添花優化手段,不可以過度依賴它是否重新渲染,因為 React 目前沒有打包票說一定執行或者一定不執行。
交流干貨系列文章匯總如下,覺得不錯點個Star,歡迎 加群 互相學習。
https://github.com/qq44924588...
我是小智,公眾號「大遷世界」作者,對前端技術保持學習愛好者。我會經常分享自己所學所看的干貨,在進階的路上,共勉!
關注公眾號,后臺回復福利,即可看到福利,你懂的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105030.html
摘要:粟例說明一下獲取子組件或者節點的句柄指向已掛載到上的文本輸入元素本質上,就像是可以在其屬性中保存一個可變值的盒子。粟例說明一下渲染周期之間的共享數據的存儲上述使用聲明兩個副作用,第一個每隔一秒對加,因為只需執行一次,所以每二個參為空數組。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! React 新特性講解及實例(一) React 新特性 Hooks 講解及實...
摘要:還可以返回另一個回調函數,這個函數的執行時機很重要。對于第二個我們可以通過返回一個回調函數來注銷事件的注冊。回調函數在視圖被銷毀之前觸發,銷毀的原因有兩種重新渲染和組件卸載。 本文是 React 系列的第二篇 React 新特性講解及實例(一) 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 什么是 Hooks Hook 是 React 16.8 的新增特性。它可...
摘要:接收一個屬性,這個組件會讓后代組件統一提供這個變量值。因此對于同一個對象而言,一定是后代元素。解決方法就是把內聯函數提取出來,如下講了這么多,我們還沒有講到其實我們已經講完了的工作原理了。 本節主要講解以下幾個新的特性: Context ContextType lazy Suspense 錯誤邊界(Error boundaries) memo 想閱讀更多優質文章請猛戳GitHub博...
摘要:第一次了解這項特性的時候,真的有一種豁然開朗,發現新大陸的感覺。在絕大多數情況下,是更好的選擇。唯一例外的就是需要根據新的來進行操作的場景。會保證在頁面渲染前執行,也就是說頁面渲染出來的是最終的效果。上面條規則都是為了保證調用順序的穩定性。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...
摘要:課程制作和案例制作都經過精心編排。對于開發者意義重大,希望對有需要的開發者有所幫助。是從提案轉為正式加入的新特性。并不需要用繼承,而是推薦用嵌套。大型項目中模塊化與功能解耦困難。從而更加易于復用和獨立測試。但使用會減少這種幾率。 showImg(https://segmentfault.com/img/bVbpNRZ?w=1920&h=1080); 講師簡介 曾任職中軟軍隊事業部,參與...
閱讀 3428·2021-11-12 10:36
閱讀 2734·2021-11-11 16:55
閱讀 2958·2021-09-27 13:36
閱讀 1616·2021-08-05 10:01
閱讀 3556·2019-08-30 15:55
閱讀 765·2019-08-30 13:01
閱讀 1906·2019-08-29 17:16
閱讀 2376·2019-08-29 16:40