You probably don't need that useCallback call
useCallback for those of you who may not know is a hook that let's us cache our functions. Now what that means if we can "save" the function. Let me break that down:
When our components re-render React creates new functions, nothing in the function actually changes but since everything is an object in JavaScript a new object is created so useCallback
basically just saves the old object.
It is common practice to wrap your functions in useCallback
, heck some wrap every function in their component in it citing performance gains etc. Thing is, that's not really true, you aren't really benefiting from doing that. In my opinion, you should only wrap a function in useCallback
if you might enter an infinite loop otherwise, if it's performance you're after React.memo
or the useMemo
hook are better alternatives.
You might be wondering "how will I know i'll enter an infinite loop?". In some cases you don't, you hit the loop, React stops it and you fix it but there is a definitive case where you could hit an infinite loop and it's also the most common:
- useEffect Having a dependency on a function that sets states
Let me break it down as simply as possible then show a code example:
Say you have a function that sets some state and you need to call it in
useEffect
and as such list it as a dependency (i.euseEffect
runs whenever the function changes). The chain would go: - The function gets called
- Sets state
- Setting state causes the component to re-render
- A new function is created
- useEffect gets called because the function has changed
- The function gets called again and so on...
The way out of it would be to wrap the function in
useCallback
so whenever we set state and the component re-renders we don't create a new function and as such useEffect never gets called. Now let's do that in code.
In the above, without// without useCallback import React, {useState, useEffect} from "react"; import axios from "axios"; function App(){ const [data, setData] = useState(null); useEffect(()=> { getData(); }, [getData]); const getData = ()=> { axios.get("https://dummydata.com").then(resp=> setData(resp.data)).catch(err=> console.log(err)); } export default App;
useCallback
we enter an infinite loop. Let's fix that.
In conclusion,// with useCallback import React, {useState, useEffect, useCallback} from "react"; import axios from "axios"; function App(){ const [data, setData] = useState(null); useEffect(()=> { getData(); }, [getData]); const useCallback(getData = ()=> { axios.get("https://dummydata.com").then(resp=> setData(resp.data)).catch(err=> console.log(err)); },[]) export default App;
useCallback
is a really powerful hook that takes care of an age old problem but it's important to remember as with all Hooks - only use it if you need it.