useCallback 常常会被用来优化效能,减少 React 不必要的 render ,但如果没有好好理解它,滥用 useCallback 的话反而会导致效能更差。今天就让我们来了解一下 useCallback 的基本用法,跟使用时机吧!
如果之前对 useEffect 够熟悉的话,useCallback 应该会蛮快上手的。它跟 useEffect 一样接受两个参数:
然後回传一个 memoized callback ,而这个 callback 就是第一个参数传进去的 callback
const memorizeCallback = useCallback(() => {
// do something
}, [])
那什麽是 memoized callback 呢? 你可以想像 useCallback 将你传进去的 function 纪录起来,并且再吐还给你,当下次元件 re-render 的时候,会根据你的 dependency array 来决定要不要生成一个新的 function ,还是将上次纪录下来的吐出来。
所以正常来说,如果没有使用 useCallback 的话,在元件中定义的 function ,当每次 re-render 都会生成一个新的。
如果还没有画面,可以看看下面的范例:
function App() {
const [count, setCount] = React.useState(0)
const callbackRef = React.useRef()
const test = () => {
console.log('test callback')
}
React.useEffect(() => {
callbackRef.current = test
}, [])
React.useEffect(() => {
console.log(test === callbackRef.current)
}, [count])
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'));)
打开 console 就会发现第一次会是 true ,而当 count 变化 re-render 後,test 的 function 就跟一开始的不一样了,所以都得到 false。
使用 useCallback :
const test = React.useCallback(() => {
console.log('test callback')
}, [])
如此一来,当之後 re-render test 都会是最一开始的的实体。
那什麽时候需要 useCallback 来帮助我们纪录 function 呢?接下来就让我们来看看范例吧!
当我们在使用打 api 的时候往往建议将 function 定义在 useEffect 当中:
React.useEffect(()=> {
function fetchData(query){
const baseUrl = `xxxxxxxx?${query}`
}
fetchData('JavaScript')
}, [])
但假设我们其他方也需要用到这个 fetchData 时,我们就必须将它定义在外面
function fetchData(query){
const baseUrl = `xxxxxxxx?${query}`
}
React.useEffect(()=> {
fetchData('JavaScript')
}, [])
React.useEffect(()=> {
fetchData('React')
}, [])
这个时候如果按照 eslint 的提醒,我们就必须把 fetchData 放到 dependency array 中,但这样做如果别的 state 改变了,会导致 re-render 然後 fetchData 又会是新的实体,就会造成 useEffect 执行。所以这个时候,其中一种的解决方案就是使用 useCallback 。
const fetchData = React.useCallback((query) => {
const baseUrl = `xxxxxxxx?${query}`
}, [])
React.useEffect(()=> {
fetchData('JavaScript')
}, [fetchData])
React.useEffect(()=> {
fetchData('React')
}, [fetchData])
这样子 fetchData 就能够很安全的放到 useEffect 的 dependency array 中了!
再来如果说 query 是从 state 来的话,我们就需在 useCallback 的 dependency array 放上 query
const [query, setQuery] = React.useState('JavaScript')
const fetchData = React.useCallback((query) => {
const baseUrl = `xxxxxxxx?${query}`
}, [query])
React.useEffect(()=> {
fetchData()
}, [fetchData])
以上就是第一种 useCallback 的使用情境,当我们需要将 function 放入 useEffect 的 dependency array 时,要先思考一下,这样子是不是想要达到的效果,还是需要用到 useCallback 将它纪录起来。明天我们将再继续聊聊,什麽样的情况下适合用 useCallback 来减少 render 次数,以及什麽时候是不必要用的情况!
今天的介绍就到这边,有什麽问题都欢迎在下方留言告诉我!
该文章同步发布於:我的部落格
<<: 自动化 End-End 测试 Nightwatch.js 与 BrowserStack
为了让使用者更直觉的修改,我希望能直接点英雄的名字就切换成可修改的输入元件,修改完後就直接存回後端。...
DAY03 建立 Datastore 和 Dataset (上) 我们都知道做 AI 最重要的就是 ...
前言 今天来讲讲 String Methods,你知道其实除了length 以外,String 还内...
前言 我们昨天介绍了 Hooks 中比较常用的 UseState 跟 UseEffect,那我们今天...
NIST出版物 NIST制定并维护了大量有关信息和信息系统的安全性和隐私性的标准,指南,建议和研究。...