useCallback和useMemo都是性能优化的手段,类似于类组件中的 shouldComponentUpdate,在子组件中使用 shouldComponentUpdate, 判定该组件的 props 和 state 是否有变化,从而避免每次父组件render时都去重新渲染子组件。发生在渲染之前。 useEffect是发生在组件渲染之后的。
useMemo
useMemo的使用场景。当依赖的数据发生变化的时候,返回的是数据,用在子组件。避免不必要的函数执行。
export default function Father(){
const [name,setName] = useState("name");
const [context,setContext] = useState("context")
return (
<div>
<button onClick={()=>{setName(name+"e")}}>name</button>
<button onClick={()=>{setContext(context+"t")}}>context</button>
<Son name={name}>{context}</Son>
</div>
)
}
export default function Son(props){
const changeName = () => {
console.log("执行changeName")
return props.name + "修改名称"
}
// 不使用useMemo,那么只要props变化了,就会执行(点击父组件修改name和context都会执行)
const otherName = changeName()
// 使用useMemo,那么该函数只会在props.name修改的时候执行(点击父组件修改name的时候才会执行)
const otherName = useMemo(()=>changeName(),[props.name])
return (
<div>
<div>{props.children}</div>
<div>{otherName}</div>
</div>
)
}
useCallback
useCallback的使用场景。当依赖的数据发生变化的时候,返回的是函数,用在父组件。避免因为不会变化的函数引起组件刷新。
export default function Father(){
const [name,setName] = useState("name");
const [change,setChange] = useState("change")
const changeFunction = () => {
console.log("changeFunction")
}
// 不使用useCallback,那么点击修改change,那么子组件就会不断打印“刷新子组件”,但是我们使用了React.memo,所以不是因为change值的改变引起子组件的刷新
// 真正的原因是函数式组件每次重新渲染,函数组件都会从头执行,这样就会导致我们给子组件绑定的函数其实是已经改变的了
const otherChangeFunction = changeFunction
// 使用useCallback,只会在依赖项发生修改的时候,才会执行。使用这个方法,现在修改change就不会导致子组件刷新
const otherChangeFunction = useCallback(()=> changeFunction,[])
return (
<div>
<button onClick={()=>{setName(name+"e")}}>name</button>
<button onClick={()=>{setChange(change+"e")}}>change</button>
<Son name={name} onClick={otherChangeFunction}></Son>
</div>
)
}
function Son(props){
console.log("刷新子组件")
return (
<div>
<div>{props.name}</div>
</div>
)
}
export default React.memo(Son)