Let's Talk About Hooks - Part 3 (useCallback and useRef)
Tags: react, javascript, beginners, webdev
Published: 2022-07-30 04:04:46

Salam, and well, hello there!

![Obi Wan Kenobi saying "Hello There"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m7mrl66d6wbbdzafz49r.png)

We are now in the third series of the React Hook series, and it is time for the next 2 hooks, which are `useCallback` and `useRef`!

These two hooks are the hook that I use most other than `useState` and `useEffect`, so you might need to keep in mind that you might, as well, use these hooks to do wonders in your app.

So, in this article, these are the topics that I will cover:

1. [`useRef` - The Reference Hook For Unmonitored Things](#section-1)
2. [`useCallback` - The Next Level of Your Callback Function!](#section-2)
3. [The Difference Between `useMemo` And `useCallback`](#section-3)
4. [The Misconception of `useEffect`, `useMemo` And `useCallback`](#section-4)
5. [Conclusion](#section-end)

Well, time to get going!

---

## <a name="section-1"></a>`useRef` - The Reference Hook For Unmonitored Things

Before we jump to the way how `useRef` works, let's just do some revision on what is `ref`, by the way.

> Refs provide a way to access DOM nodes or React elements created in the render method. - React Documentation

So, to access your DOM elements, let's say, your `<div>` component, you pass your component to the ref, so you don't have to do something like `document.getElementById()` or something similar. Plus, using `ref` helps you to keep track of the components to do a lot of things, like programmatically styling the components, or extracting the form's values.

Don't get me wrong here. I wouldn't say that `document.getElementById()` shouldn't be used, in fact, I advise you to actually learn how to use them, so you can also understand how `ref` simplifies things in React.

So, how is the syntax, you ask? Well, look below!

```jsx
const theRef = useRef(initialValue);
```

Yes, it is that simple. The hook only needs one parameter, which is the initial value. Hmmmm, it should be the component, right?

Well, before mounting, your component isn't there yet, but later on, the component will be mounted and ready to be referred. So, `useRef` will handle this hassle, and update with the component that you will bind later on.

But then, initialization will always be undefined? Hmmm, about that, I will get back to this to explain first how to use `useRef` fully, and then we will get back to this question.

So, `useRef` will return the `ref`, which is the thing that you want to refer to. How can I bind this to the component?

```jsx
const theRef = useRef();

return (
  <div ref={theRef} />
);
```

In your component, you can pass `ref` props to any of the HTML components, and then pass the created `ref` to the prop. So, if you console the value of `theRef` later on, you will get the component object, and from there, you can do a lot of things, such as `theRef.target.classList.add('force')`!

But bear this in mind! Ref is not something monitored by React lifecycle. That means, the ref is not affected by rerenders at all, but instead only affected by the changes of the `ref` itself. So, that means, we can update the ref too? The answer is yes! As much as you do DOM manipulation, that is you updating the ref, but it doesn't trigger the rerender.

So, if I can update the ref without triggering the rerender, does that mean that throughout the React lifecycle, the `ref` value will not be affected? Yes, it won't!

You can actually use `useRef` for something other than DOM manipulation. Let's say, you want to keep track of something, maybe the number of clicks, but you don't want to trigger the rerenders, then `useRef` will be a perfect hook for you! With this, initializing `ref` with something will make sense.

Let's look to another example of `useRef` that is not a DOM-thing.

```jsx
const clickAmount = useRef(0);

const handleClick = (e) => {
  e.preventDefault();
  clickAmount++;
}

return (
  <button onClick={handleClick} />
);
```

What do you think if I click the button above? The `handleClick` will add 1 to `clickAmount` each time. However, there will be no rerender. Yes, no rerenders!

Okay, let's add some complexity to the component.

```jsx
const [theState, setTheState] = useState(0);
const clickAmount = useRef(0);
const randomThing = 0;

const handleClick = (e) => {
  e.preventDefault();
  clickAmount++;
}

const handleUpdateState = (e) => {
  e.preventDefault();
  setTheState((prevState) => prevState + 1);
}

const handleUpdateVar = (e) => {
  e.preventDefault();
  randomThing++;
}

return (
  <div>
    <button name="updateRef" onClick={handleClick} />
    <button name="updateState" onClick{handleUpdateState} />
    <button name="updateVar" onClick{handleUpdateVar} />
  </div>
);
```

Whoaaa, a lot of complexity here. First, let the force calm you for a second, and let me guide you through the way.

Let us consider several cases:
- I click `updateVar` and then I click `updateState`
- I click `updateVar` and then I click `updateRef`
- I click `updateRef` and then I click `updateState`

**FOR THE FIRST CASE**, when I click `updateVar`, the value of `randomThing` will increase by 1. Then I click `updateState` and `theState` will increase by 1. But what do you think happened to `randomThing`? The answer is, that it will reset to 0 because the component is rerendered and all variables that are not wrapped inside the hook or functions will be reset to the initial value that is assigned to the variable.

**FOR THE SECOND CASE**, when I click `updateVar`, the value of `randomThing` will increase by 1. Then I click `updateRef`, and the value of `clickAmount` will increase by 1. But, what do you think happened to `randomThing`? The answer is, it won't change! Remember that `useRef` didn't trigger the rerenders, so `randomThing` will keep its value until the rerenders.

**FOR THE THIRD CASE**, when I click `updateRef`, the value of `clickAmount` will increase by 1. Then I click `updateState`, and `theState` will increase by 1. But, what do you think happened to `clickAmount`? The answer is, that `clickAmount` won't change! Yes, as I say that `ref` won't be bothered by rerenders, so the `clickAmount` won't be reset and it keeps the value until the component unmount.

To summarize this
- State will always trigger rerenders.
- Declared variables inside the component, that are not wrapped in hooks or functions, will always be reset during rerenders.
- Ref, on the other hand, will keep the value, even after the rerenders since `ref` is not affected by the rerenders. Unless unmounting happens, then all inside components become non-existent, including refs.

Sheesh, after the long explanation of `useRef`, let's dive into `useCallback`. Brace yourself for yet another long explanation 🥶

---

## <a name="section-2"></a>`useCallback` - The Next Level of Your Callback Function!

Let's get knowledge of what callback is!

> A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. -MDN Web Docs

As you can see, a callback function is indeed, just another kind of function. The way of writing is the same, it is just how you use the function.

```jsx
const useForce = () => {
  // Do anything you want
}

const approachEnemy = (callback) => {
  // Do what you need to
  callback();
}

approachEnemy(useForce);
```

The first function, `useForce` is the function for when you will use the force to do things. And the second function, `approachEnemy` is the function for when you want to approach the enemy. If you noticed, I passed `useForce` inside `approachEnemy` so that means that I will `useForce` every time I `approachEnemy`. `useForce` is what we call the callback function. With this way of writing function, we can change what we want to pass to the first function, providing flexibility to the first function. With this, instead of `useForce`, I can instead `useLightning` to `approachEnemy` too! 😈

Well, if you ever passed a function as a prop to a component, that is a callback as well!

```jsx
const CompParent = () => {
  const myFn = () => {}

  return <CompChild onFunc={myFn} />
}

const CompChild = ({ onFunc }) => (
  <button onClick={onFunc} />
);
```

But, of course, adding events and all sorts of things makes it different, but passing a function as a parameter is considered a callback function. I hope you get the idea!

Oooooookay, back to the topic. So, for a callback function, it matters when you want to trigger the function. Let's say if I pass a callback function, when do I want it to trigger? You can put it anywhere in the function to call the passed callback, but it might as well be complex when you throw something else in the mix, like loops and conditionals.

Going back to the React topic, we are usually writing the functions to handle things, like handling events, triggering API, or maybe your DOM manipulations like focusing and blurring elements.

```jsx
const handleClick = (e) => {
  e.preventDefault();
};

return <button onClick={handleClick} />;
```

Do you know, that `onClick` is an event function that triggers when the user clicks the element? Passing a function to the `onClick` only means that `handleClick` is a callback function. `handleClick` won't trigger, unless the `onClick` function is triggered. But doing this way, every time you click the button, the function will be triggered.

Let's get to the more complex component!

```jsx
const [anakinSide, setAnakinSide] = useState('jedi');
const announceSide = () => {
  console.log(`I am now a ${anakinSide}`);
};

return (
  <div>
    <button onClick={announceSide} />
    <button onClick={() => setAnakinSide('sith')} />
  </div>
);
```

So, for this case, I would like to announce which side Anakin is currently on when I click the button. And then, I create another button to change Anakin's side. But just imagine, it must be annoying if I keep telling you the same thing a thousand times that Anakin is a jedi, when you know he didn't change side yet, unless he is! So, I would like to only announce Anakin's side, only when there is a change in Anakin's side.

To do this, `useCallback` will serve its purpose!

```jsx
const [anakinSide, setAnakinSide] = useState('jedi');
const announceSide = useCallback(() => {
  console.log(`I am now a ${anakinSide}`);
}, [anakinSide]);

return (
  <div>
    <button onClick={announceSide} />
    <button onClick={() => setAnakinSide('sith')} />
  </div>
);
```

Now, I wrapped `announceSide` function with a `useCallback` hook, and I passed a dependency, which is `anakinSide`. When this happens, every time you click the button to announce which side is Anakin is on, it will check `anakinSide` cache to see if there is any changes to the previous change. If there is no changes, then `announceSide` won't trigger! That means, the component will only announce when Anakin changes side, despite many attempts to do announcement. So, let's see how callback is written!

```jsx
const theFn = useCallback(callback, [arrayOfDependencies]);
```

So, only two things that you need to pass to the `useCallback` hooks, which are the callback function, and the array of dependencies. When there is any changes to any of the dependencies, the callback will be triggered.

Well, this hooks sound similar to what you read before? 🤔

## <a name="section-3"></a>The Difference Between `useMemo` And `useCallback`

As you guessed, `useMemo` and `useCallback` indeed has 100% similar structure of using the hook. However, there are some points that you need to pay attention to.

First, `useCallback` should be used for, as you guessed, the callback function. That means, the purpose is to run the function, but it will try to memoize the function based on the dependencies. While `useMemo` memoize not just the dependencies, but the value itself.

To put it into context, let's dive into the following examples.

```jsx
const saberColorOptions = useMemo(() => {
  return ["blue", "green", "purple", "red"];
}, []);

const shoutLikeChewbacca = () => useCallback(() => {
  alert("roarrrrrrr");
}, [];
```

For `useMemo` example, I declared `saberColorOptions` that returns the array. Although I didn't put any dependency, `useMemo` will always cache the value. You can say that `useMemo` will "keep his eye on" the value of `saberColorOptions` if there is any change. So, `saberColorOptions`' value won't change, despite thousands of rerenders triggered.

For `useCallback` example, I create a function called `shoutLikeChewbacca`. If I passed the function to another function as a callback, it will always run once, since I didn't pass any dependency. So, it keeps the cache of the function, and not the value.

`useMemo` is used to assign value and keep cache, while `useCallback` is to cache the dependency to run the function.

## <a name="section-4"></a>The Misconception of `useEffect`, `useMemo` And `useCallback`

These three hooks require 2 things, which is a function, and array of dependencies. So, I would understand the difference between `useMemo` and `useCallback`, but now `useEffect`?

You need to know that **`useEffect` is a hook that shaped based on component lifecycles**. It will always trigger during the rerenders, while it meets the change of one of the dependencies. While **`useMemo` and `useCallback` is NOT dependent to component lifecycles, but rather the cache**. That means the rerenders doesn't affect the hook, but instead the changes of the dependencies. This might look the same at first, but let me give an example.

Let's say I have a state called `warshipName`. If I trigger the state setters, I will trigger the rerenders. `useEffect` which contains `warship` as a dependency will be triggered, whether `warshipName` changes value or not, as long as the state setters is triggered. `useMemo` and `useCallback` on the other hand, monitor its cache instead, so they will only be triggered if `warshipName` value changes.

Other than that, since `useEffect` is based on component lifecycles, it is understandable that `useEffect` is one of the most common hook used to handle effects after rerenders. However, `useMemo` and `useCallback` will create a cache that monitors the value of all dependencies. Which means, that using `useMemo` and `useCallback` ALWAYS come with a cost. Use `useMemo` and `useCallback` when there is necessity or when it involves some certain of complexity. The example given is actually quite simple, where it is better if you get rid of the hooks altogether, and just use a simple callback function instead. Like I said in previous article on `useMemo`, only use the hooks when it uses a lot of resources, so you won't have to repetitively execute the same function only when necessary.

## <a name="section-end"></a>Conclusion

Yeah, I have covered 6 hooks at this point, and there are still a lot of hooks provided by React for your perusal. And throughout my experiences, I keep studying on how people use these hooks to create their own hook. In my early years, I was so naive to try to optimise everything using hooks, but little did I know that I did it backward most of the time. Well, the learning process never stop!

My take is, memoization doesn't equal to performance. Memoization on simple things often jeopardise performance more than it shouldn't. At one phase, you wish that you can abstract a lot of things, just to realise you make things more complicated and slows down the performance.

However, never falter, for these hooks do not exist for no reason, it is just you need to really know when to actually use it! Just learn how to use it, apply it in your personal projects, and see how it actually is in action, so you already have a hook when the time comes.


![The High Ground Meme](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oah8m4txg40pl36o927p.jpeg)

Well, until next time, keep yourself at the high ground at all times, and peace be upon ya!