React Hooks系列之useCallback
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 组件就不会跟着渲染啦