本系列將講述 React Hooks 的使用方法,從 useState 開始,將包含以下內容:css
掌握 React Hooks api 將更好的幫助你在工做中使用,對 React 的掌握更上一層樓。本系列將使用大量實例代碼和效果展現,很是易於初學者和複習使用。react
上一章,咱們學習了 useCallback 來進行性能優化,關於性能優化還有另外一個 hook api,那就是 useMemo,下面咱們一塊兒經過一個例子來看看。api
依然是計數器示例,建立2個計數器,並能區分當前是奇數或者偶數,爲了模擬點擊按鈕時包含大量的計算邏輯影響性能,在判斷偶數的方法中添加了沒有用的計算邏輯,爲了讓性能差的明顯。代碼以下數組
Counter.tsx緩存
import React, { useState } from 'react'
function Counter() {
const [counterOne, setCounterOne] = useState(0)
const [counterTwo, setCounterTwo] = useState(0)
const incrementOne = () => {
setCounterOne(counterOne + 1)
}
const incrementTwo = () => {
setCounterTwo(counterTwo + 1)
}
const isEven = () => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}
return (
<div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven() ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
)
}
export default Counter
複製代碼
App.tsx性能優化
import React from 'react'
import './App.css'
import Counter from './components/27.Counter'
const App = () => {
return (
<div className="App"> <Counter /> </div>
)
}
export default App
複製代碼
頁面展現以下函數
咱們發現點擊第一個按鈕有較長的延遲,由於咱們的判斷偶數的邏輯中包含了大量的計算邏輯。可是,咱們點擊第二個按鈕,也有較長的延遲!這很奇怪。性能
這是由於,每次 state 更新時,組件會 rerender,isEven 會被執行,這就是咱們點擊第二個按鈕時,也會卡的緣由。咱們須要優化,告訴 React 不要有沒必要要的計算,特別是這種計算量複雜的。學習
在咱們的示例中,咱們要告訴 React,在點擊第二個按鈕時,不要執行 isEven 方法。這時就須要 useMemo hook 登場了。優化
與 useCallback 的用法相似。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
複製代碼
返回一個 memoized 值。 把「建立」函數和依賴項數組做爲參數傳入
useMemo
,它僅會在某個依賴項改變時才從新計算 memoized 值。這種優化有助於避免在每次渲染時都進行高開銷的計算。記住,傳入
useMemo
的函數會在渲染期間執行。請不要在這個函數內部執行與渲染無關的操做,諸如反作用這類的操做屬於useEffect
的適用範疇,而不是useMemo
。若是沒有提供依賴項數組,
useMemo
在每次渲染時都會計算新的值。你能夠把 useMemo 做爲性能優化的手段,但不要把它當成語義上的保證。 未來,React 可能會選擇「遺忘」之前的一些 memoized 值,並在下次渲染時從新計算它們,好比爲離屏組件釋放內存。先編寫在沒有 useMemo 的狀況下也能夠執行的代碼 —— 以後再在你的代碼中添加 useMemo,以達到優化性能的目的。
首先引入 useMemo
import React, { useState, useMemo } from 'react'
複製代碼
而後將 isEven 方法使用 useMemo 改寫,返回值賦給 isEven
const isEven = useMemo(() => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}, [counterOne])
複製代碼
最後記得修改 isEven 使用的地方,已經從一個方法變爲了一個變量
{
isEven ? 'even' : 'odd'
}
複製代碼
完整代碼以下
Counter.tsx
import React, { useState, useMemo } from 'react'
function Counter() {
const [counterOne, setCounterOne] = useState(0)
const [counterTwo, setCounterTwo] = useState(0)
const incrementOne = () => {
setCounterOne(counterOne + 1)
}
const incrementTwo = () => {
setCounterTwo(counterTwo + 1)
}
const isEven = useMemo(() => {
let i = 0
while (i < 1000000000) i += 1
return counterOne % 2 === 0
}, [counterOne])
return (
<div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
)
}
export default Counter
複製代碼
效果以下
咱們看到點擊第二個按鈕時,不會有任何卡頓,這是由於使用了 useMemo 只依賴了 counterOne 變量,點擊第二個按鈕時,isEven 讀取的是緩存值,不須要再從新計算是否爲偶數。
useCallback 是緩存了函數自身,而 useMemo 是緩存了函數的返回值。
本章經過示例展現了 useMemo 在性能優化中的做用。經過緩存函數的返回值,避免沒必要要的調用,從而避免了組件 rerender。
最後有分析了 useMemo 與 useCallback 的區別,即 useMemo 是緩存了函數的返回值,useCallback 是緩存了函數自身。這兩個 api 都是性能優化的方法。