useCallback主要就是對函數進行緩存,useCallBack這個Hooks主要是解決React.memo不能緩存事件
的問題
useCallBack(fn, dependencies) :fn想要緩存的函數,dependencies有關是否更新 fn 的所有響應式值的一個列表
比如:UseCallBackOptimize組件傳遞了一個事件函數給ChildCom2、ChildCom3,只要其中一個子組件調用這個事件就會影響到另一個子組件重新渲染一次,React.memo可以解決傳值問題,但解決不了傳遞事件的問題。
示例:
styles.module.css
.container {width: 500px;height: 200px;border: 1px solid;margin: 0 auto;
}.btnContainer {text-align: center;
}.childComContainer {display: flex;justify-content: space-between;
}
import { useState, useCallback } from 'react'
import ChildCom2 from './components/ChildCom2'
import ChildCom3 from './components/ChildCom3'
import styles from "./styles.module.css"
export default function UseCallBackOptimize() {// 這是UseCallBackOptimize組件自身維護的狀態const [counter, setCounter] = useState(0);// 這是傳遞給ChildCom2組件的數據const [counter1, setCounter1] = useState(0);// 這是傳遞給ChildCom3組件的數據const [counter2, setCounter2] = useState(0);//之所以子組件使用了memo后都無法阻止子組件之間互相影響,是因為每次重新渲染的時候都會生成一個圈新的test函數function test() {console.log("test");}console.log("UseCallBackOptimize組件渲染了")return (<div className={styles.container}><div className={styles.btnContainer}><div>{counter}</div>{/*點擊修改數字時,ChildCom2和ChildCom3組件都會更新,原因看test上面*/}<button onClick={() => setCounter(counter + 1)}>+1</button></div><div className={styles.childComContainer}><ChildCom2 counter={counter1} setCounter={setCounter1} test={test}/><ChildCom3 counter={counter2} setCounter={setCounter2} test={test}/></div></div>);
}
import { memo } from "react"
function ChildCom2(props) {// 該子組件維護了一個自身的狀態// const [counter, setCounter] = useState(0);console.log("ChildCom2 渲染了")return (<div style={{width: "200px",height: "100px",border: "1px solid"}}>ChildCom2<div>{props.counter}</div><button onClick={() => props.setCounter(props.counter + 1)}>+1</button><button onClick={() => props.test()}>test</button></div>);
}export default memo(ChildCom2);
import { memo } from "react"
function ChildCom3(props) {// 該子組件維護了一個自身的狀態// const [counter, setCounter] = useState(0);console.log("ChildCom3 渲染了")return (<div style={{width: "200px",height: "100px",border: "1px solid"}}>ChildCom3<div>{props.counter}</div><button onClick={() => props.setCounter(props.counter + 1)}>+1</button><button onClick={() => props.test()}>test</button></div>);
}export default memo(ChildCom3);
本來調用ChildCom2的函數ChildCom3是不應該重新渲染的,使用useCallBack可以解決這個問題,兩個子組件什么都不變的
解決后示例
import { useState, useCallback } from 'react'
import ChildCom2 from './components/ChildCom2'
import ChildCom3 from './components/ChildCom3'
import styles from "./styles.module.css"
export default function UseCallBackOptimize() {// 這是UseCallBackOptimize組件自身維護的狀態const [counter, setCounter] = useState(0);// 這是傳遞給ChildCom2組件的數據const [counter1, setCounter1] = useState(0);// 這是傳遞給ChildCom3組件的數據const [counter2, setCounter2] = useState(0);//todo 之所以子組件使用了memo后都無法阻止子組件之間互相影響,是因為每次重新渲染的時候都會生成一個圈新的test函數/* function test() {console.log("test");} */// 使用了 useCallback 之后,針對test函數就做了一個緩存,如果依賴某個參數如counter,就在參數2[]里面傳入進去const newTest = useCallback(function test() {console.log("test");}, [])console.log("UseCallBackOptimize組件渲染了")return (<div className={styles.container}><div className={styles.btnContainer}><div>{counter}</div><button onClick={() => setCounter(counter + 1)}>+1</button></div><div className={styles.childComContainer}><ChildCom2 counter={counter1} setCounter={setCounter1} test={newTest}/><ChildCom3 counter={counter2} setCounter={setCounter2} test={newTest}/></div></div>);
}