useCallback介紹
useCallback 可以說是 useMemo 的語法糖,能用 useCallback 實現,都可以用 useMemo,常用語 react 的性能優化。 在 react 中我們經常面臨一個子組件渲染優化的問題,尤其是在向子組件傳遞函數 props 時,每次 render 都會創建新函數,導致子組件不必要的渲染,浪費性能,這個時候,就是useCallback 的用武之地,useCallback 可以保證,無論 render 多少次,我們的函數都是同一個函數,減少了不斷創建的開銷。
const memoCallback = useCallback(callback, array)
返回一個memoized 回調函數。
- callback 是一個函數用於處理邏輯
- array 控制 useCallback 重新執行的數組,array 改變時才會重新執行useCallback
- 數組,每次更新都會重新計算
- 空數組,只會計算一次
- 依賴對應的值,對應的值發生變化重新計算
- useCallback(fn, deps) 相當於 useMemo(() => fn, deps)
useCallback 使用
function App () {
const [ count, setCount ] = useState(0)
const add = useCallback(() => count + 1, [count])
return (
<div>
點擊次數: { count }
<br/>
次數加一: { add() }
<button onClick={() => { setCount(count + 1)}}>點我</button>
</div>
)
}
應用場景:
import React, { useState } from 'react'
class Test extends React.PureComponent {
render() {
console.log("Test Render")
return <div>
<h1>{this.props.text}</h1>
<button onClick={this.props.onClick}>改變文本</button>
</div>
}
}
const Parent = () => {
console.log("Parent Render")
const [txt, setTxt] = useState(123)
const [n, setN] = useState(0)
return (
<div>
<Test text={txt} onClick={() => {
setTxt(123)
}}></Test>
<input type="number"
value={n}
onChange={
e => {
setN(parseInt(e.target.value))
}
}></input>
</div>
)
}
const App = () => {
return (
<div>
<Parent />
</div>
)
}
export default App
理論來說,Test 作為純組件,只有在傳入發生改變的時候才會重新渲染,當點擊改變文本的按鈕時,setTxt所更改的值與本身Txt的值相同,所以Test 組件不會重新渲染,不會打印test Render
問題所在就是,當Parent 組件中的其他值發生改變的時候,Parent 組件便會重新渲染,而Test 組件中Txt 的值雖然沒有改變, 但傳入的() => { setTxt(123) } 作為方法對象,會創建一個新的地址棧, 兩次地址的指向不同了,所以會認為傳入的值發生了改變,所以 Test 組件發生了重新渲染

這樣的渲染浪費了不必要的性能,所以 useCallback 就是用來解決這一問題的
import React, { useState,useCallback } from 'react'
class Test extends React.PureComponent {
render() {
console.log("Test Render")
return <div>
<h1>{this.props.text}</h1>
<button onClick={this.props.onClick}>改變文本</button>
</div>
}
}
const Parent = () => {
console.log("Parent Render")
const [txt, setTxt] = useState(123)
const [n, setN] = useState(0)
const hhh = useCallback(()=> {
setTxt(223)
},[])
return (
<div>
<Test text={txt} onClick={hhh}></Test>
<input type="number"
value={n}
onChange={
e => {
setN(parseInt(e.target.value))
}
}></input>
</div>
)
}
const App = () => {
return (
<div>
<Parent />
</div>
)
}
export default App

這樣當改變n的值時 Test 組件就不會跟着渲染啦
