---
# System prepended metadata

title: React Hook - useCallback
tags: ['Javascript, React']

---

#  React Hook - useCallback 

###### tags: `Javascript, React`

> 1. 使用起來跟 useMemo 非常像，一樣是可以確保 referencial equality ，確保返回的函式不會因為任意的畫面 re-render 而被重新創造出來
> 2. 第二個比較常用到的地方則是當創造一個 function 時非常非常慢時
> 3. 與 useMemo 最大的差異是 useCallback 返回其函式本身 / useMemo 返回其函式的值

# 範例說明

這次的 DEMO 主要會操作這個 input form 主要改變數字的時候下方的 list 也會同時顯示並且顯示 本身, +1 , +2

並且可以更改 backgroundColor 藉由按鈕 toggle theme 達成

![](https://i.imgur.com/rSaIiV6.png)

## App.js
```javascript=
import './App.css';
import React,{useState} from 'react';
import List from './List';

export default function App() {

  const [number, setNumber] = useState(1);
  const [dark, setDark] = useState(false);

  const getItems = () => {
    return [number, number + 1, number + 2];
  }

  const theme = {
    backgroundColor:dark? '#333':'#FFF',
    color:dark? '#FFF': '#333',
    marginLeft:'3rem',
    marginTop:'3rem'
  }

  return (
    <div style={theme}>
      <input type="number" value={number} onChange={e => setNumber(parseInt(e.target.value))} />
      <button onClick={() => setDark(prevDark => ! prevDark)}>Toggle theme</button>
      <List getItems ={getItems}></List>
    </div>
  );
}

```

## List.js
```javascript=
import React,{useState,useEffect} from 'react'

export default function List({getItems}) {

    const [items, setItems] = useState([])

    useEffect(() => {
        setItems(getItems())
        console.log('Updating Items');
    }, [getItems])
    return  items.map(item => <div key={item}>{item}</div>)
}
```

在 List.js 內有使用 useEffect 來操作當 getItems 更新了就會印出字樣 Updating Items

![](https://i.imgur.com/GVD2bY4.png)


可是問題來了，當我使用 toggle theme 按鈕時他卻也觸發了

![](https://i.imgur.com/rZUX6l5.png)

然而會發生這種情況是因為畫面的 re-render (更新 state dark )的時候 getItems function 都會被重新創造出來，所以儘管裡面的數字相同，但是 function 是新的所以 useEffect 會再把字樣 log 出來一次

在這種情況下就可以使用 useCallback (這邊的使用情境跟 useMemo 很像)，因為它可以監聽變數，只有在變數改變的情況下才會重新創造 getItems function 

```javascript=
 const getItems = useCallback(() => {
    return [number, number + 1, number + 2];
  },[number])
```
所以當使用完畢後，我們 toggle theme 就算 re-render 畫面，也不會在觸發創造新的 getItems function 因為它已經使用 useCallback 監聽變數 number 了

## useCallback 以及 useMemo 最大的區別

> useMemo: Returns and stores the calculated value of a function in a variable
> useCallBack: Returns and stores the actual function itself in a variable


useMemo 會返回指派給變數的函式的值

useCallback 則是會返回指派給變數的函式的本身


所以你可以這樣操作 useCallback 

```javascript=
 const getItems = useCallback((incrementor) => {
    return [number+ incrementor, number + 1+incrementor, number + 2+incrementor];
  },[number])
```


因為返回的是函式本身所以是可以代入參數進去使用的
```javascript=
import React,{useState,useEffect} from 'react'

export default function List({getItems}) {

    const [items, setItems] = useState([])

    useEffect(() => {
        setItems(getItems(50))
        console.log('Updating Items');
    }, [getItems])
    return  items.map(item => <div key={item}>{item}</div>)
}
```
呈現結果如下
![](https://i.imgur.com/NRq0Vj6.png)


所以同樣的你會使用到 useCallback 最主要的情況也是在你要注意 referencial equality 的時候，因為每次 re-render 的時候都會創造新的 function 因此需要使用到 useCallback 來確保只有在監聽的變數更新時，才會更新 function 

以這邊的例子來說明的話就是，確保了只要不是 number 更新的情況下， getItems 的 funtion 是不會被改變的因此可以確保它的 referencial equality 


## 第二種使用情景就是當創造一個 function 時非常非常慢

如下方的範例可以看出，要執行這個 slowFunction 顯然需要非常多的時間，所以我們不能在每次 re-render 畫面的時候都觸發重新創造這個函式，因此使用 useCallback 來確保只有當 number 更新時才會觸發重新創造這個 function 增進其效能

```javascript=

function slowFunction(num){
  console.log('call slow function');
  for(let i=0; i<1000000000; i++ ){}
  return num*2;
}

const doubleNumber = useCallback(()=>{
      returm slowFunction(number
      )},[number])
```