https://juejin.cn/post/6844904101445124110#heading-6
useCallback 的作用
useCallback是用來優化性能的,
但是,如果不了解它是怎么優化性能的,建議還是不要用了,因為,容易出現bug。
useCallback返回一個函數,只有在依賴項變化的時候才會更新(返回一個新的函數)。
import React, { useState, useCallback } from 'react'; import Button from './Button'; export default function App() { const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const [count3, setCount3] = useState(0); const handleClickButton1 = () => {setCount1(count1 + 1)}; const handleClickButton2 = useCallback(() => { setCount2(count2 + 1); }, [count2]); return ( <div> <div> <Button onClick={handleClickButton1}>Button1</Button> </div> <div> <Button onClick={handleClickButton2}>Button2</Button> </div> <div> <Button onClick={() => {setCount3(count3 + 1); }}> Button3 </Button> </div> </div> ); } 鏈接:https://juejin.cn/post/6844904101445124110
// Button.jsx import React from 'react'; const Button = ({ onClickButton, children }) => { return ( <> <button onClick={onClickButton}>{children}</button> <span>{Math.random()}</span> </> ); }; export default React.memo(Button);
在案例中可以分別點擊Demo中的幾個按鈕來查看效果:
- 點擊 Button1 的時候只會更新 Button1 和 Button3 后面的內容;
- 點擊 Button2 會將三個按鈕后的內容都更新;
- 點擊 Button3 的也是只更新 Button1 和 Button3 后面的內容。
經過useCallback優化后的 Button2 是點擊自身時才會變更(更新),其他的兩個只要父組件更新后都會變更(這里Button1 和 Button3 其實是一樣的,無非就是函數換了個地方寫)。
注:Button組件里面的React.memo這個方法,會對props做一個淺層比較,如果props沒有發生改變,則不會重新渲染此組件。沒有用useCallback包括的函數,每次都會重新聲明一個新的方法,新的方法盡管和舊的方法一樣,但是依舊是兩個不同的對象,React.memo對比后發現對象props改變,就重新渲染了。
用useCallback包括的函數,根據依賴是否發生變化,才會決定是否返回一個新的函數,如果沒有變化,就會返回上一次緩存的函數。
const [count1, setCount1] = useState(0); const [count2, setCount2] = useState(0); const handleClickButton1 = () => { setCount1(count1 + 1) }; const handleClickButton2 = useCallback(() => { setCount2(count2 + 1) }, [count2]); return ( <> <button onClick={handleClickButton1}>button1</button> <button onClick={handleClickButton2}>button2</button </> )
上面這種寫法在當前組件重新渲染時 handleClickButton1
函數會重新渲染,handleClickButton2
useCallback 里面的函數也會重新渲染。反而加了 useCallback ,在執行的時候還多了 useCallback 中對 count2
的一個比較邏輯。
useCallback 是要配合子組件的 shouldComponentUpdate
或者 React.memo
一起來使用的,否則就是反向優化,這就是前面說的bug。
useMemo 的作用
useMemo是在render期間執行的。所以不能進行一些額外的副操作,比如網絡請求等。
傳遞一個創建函數和依賴項,創建函數會需要返回一個值,只有在依賴項發生改變的時候,才會重新調用此函數,返回一個新的值。
沒有用useMemo
// ... const [count, setCount] = useState(0); const userInfo = { // ... age: count, name: 'Jace' } return <UserCard userInfo={userInfo}>
用了useMemo
// ... const [count, setCount] = useState(0); const userInfo = useMemo(() => { return { // ... name: "Jace", age: count }; }, [count]); return <UserCard userInfo={userInfo}>
第一段沒有用useMemo的代碼,userInfo 每次都將是一個新的對象,無論 count
發生改變沒,都會導致 UserCard 重新渲染,而下面的則會在 count
改變后才會返回新的對象。
怎么用useMemo表示useCallback
useCallback(fn,[m]);
等價於
useMemo(() => fn, [m]);
結語
useCallback緩存的是函數,useMemo 緩存的是函數的返回就結果。
useCallback 是來優化子組件的,防止子組件的重復渲染。
useMemo 可以優化當前組件也可以優化子組件,優化當前組件主要是通過 memoize 來將一些復雜的計算邏輯進行緩存。當然如果只是進行一些簡單的計算也沒必要使用 useMemo。