The TestHooks component logs on mount and unmount and fetches data from the JSONPlaceholder API when a button is clicked.
Use effects when the logic needs to run as a side effect of rendering or state changes parallel to an action like syncing with external systems, fetching data on mount, setting up subscriptions, or running cleanup.
The effect runs after every render. That can cause unnecessary work or create infinite loops if the effect updates state.
Forgetting dependencies can make effects run too often. Heavy work inside effects, like API calls or DOM measurements on every render, slows the app down. Missing cleanup can also leave processes running when no longer in use.
useCallback addresses the issue of unnecessary child component re-renders when the component is updated. In React, any local function defined within a component is recreated and thus provided with a different memory address during a render. When such a function is provided as a prop to a child component, the child will be re-rendered if the new memory address of the prop is not equivalent to the memory address it had during the previous render. useCallback returns the memoized version of a callback that only changes if a value from its dependency array changed. This creates a stable reference to the callback function between renders. In the event that the values within the dependency array do not change, the child component's props will retain their previous memory address, eliminating unnecessary re-renders.
Both of these hooks are utilized to memoize values in React and increase performance. However, a key difference is what gets stored in memory. useMemo caches the result of a function call. This is useful for optimizing expensive calculations by not recalculating the value. On the other hand useCallback stops parent component re-renders from creating new handler props that force memoized children to re-render by creating a cached function reference.
useCallback is not required if you do not pass this function into an optimized child component (React.memo) or use the function as a dependency array to another hook. In a situation where you just need to provide a function as an event handler for a simple element inside the component, creating a new function on each render is a fairly costless task and won't hurt performance in any way. However, using useCallback unnecessarily may reduce performance since the hook adds overhead. Specifically, React has to keep track of the array of dependencies given and check their values for equality on each render. Because useCallback comes with additional complexity, it should be used only in the specific case that you identify as re-creating functions with new references on every render.
useMemo speeds things up by storing the outcome of a cost-intensive computation across renders. Instead of recalculating the result with every render, React only recalculates the result if something in the dependency list that was passed into useMemo changed. This means if the component is rendered for some other reason, the heavy calculation on a large list of numbers can be skipped.
You should not use it with simple calculations when the values passed are primitives or anything that doesn't require an immense computational load. useMemo has a little bit of performance overhead because React needs to save it somewhere in memory and then on each render needs to calculate if anything in the dependency list has changed to calculate again. You really want to use useMemo when the calculation is very expensive.
Without useMemo the large list of numbers calculation will happen each time the component is rendered. Since this is a very slow calculation, each render will slow down your application as it has to recalculate that slow function before being able to continue.