Hook up with the React Hooks

Rahul Biswas
7 min readMay 6, 2020

--

Day 3 of React Learning — Milestone 2 (Week 2)

Welcome to the 3rd day of React learning. Today we will discuss about React Hooks - one of the most trending buzzwords of the front-end development industries. We have discussed how React Hooks works, how to use it, what are the advantages of using React Hooks over states and props, and how to optimize React apps using Hooks. So, let’s jump into the article.

1. What are Hooks in React?

React Hooks lets us use state, and other React features without having to define a JavaScript class. It’s like being able to take advantage of the cleanliness and simplicity of a Pure Component and state and component lifecycle methods. This is because Hooks are just regular JavaScript functions! This lends itself to cleaner and less clunky code.

In the following examples, we can see that not only is the code a lot smaller but also the saved space certainly adds up for larger components - it’s also a lot more readable, which is a huge advantage of Hooks.

Example (with hooks):

Example (without hooks):

2. Stale Closure

What is Closure?
As we’ve learned about the closure in our Milestone 1 (Day 2)’s lesson that,

Closure is one of the powerful default behavior of JavaScript, which is interesting but confusing at the same time.
It’s known to us that in JS a child function can access all the function variables, objects, etc. from the parent class. But it is more interesting that even if the parent function is returned, the child function can still access the function variables, object, etc. from the parent class. Because the function properties are stored in memory. This feature is known as Closure in JavaScript. Closures let us save state - as such, they can often be used in place of objects.

Example:

function closuresDemo() {
var x = 10;
return function() {
var y = 20;
console.log(‘Sum: ‘ + (x + y));
}
}

In React, if we want to match with the real API, our state must have to be a variable rather than a function. If we wrap up variable within the function and call them we will encounter a bug, which is known as Stale Closure

Example

When we destructured foo from the output of useState, it refers to the _val as of the initial useState call & never changes again! This is not what we want; we generally need our component state to reflect the current state, while being just a variable instead of a function call!

3. Closure in Modules

We can resolve the error stated in the previous section, by moving our closure inside another closure!

Example:

This example tracks the component state _val. This allows MyReact to “render” our function component, which allows it to assign the internal _val value every time with the correct closure:

4. Rules of using Hooks

Hooks are JavaScript functions, but you need to follow two rules when using them.

i) Only call Hooks at the Top Level
We can’t call Hooks inside loops, conditions, or nested functions. Instead, we can always use Hooks at the top level of our React function. By following this rule, we ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

ii) Only Call Hooks from React Functions
In spite of being a JavaScript function, we can’t call Hooks from regular JavaScript functions. Rather, we can:

  • Call Hooks from React function components.
  • Call Hooks from custom Hooks

5. How to test components that use Hooks?

From React’s point of view, a component using Hooks is just a regular component.
For example, let’s say we have a counter component

We’ll test it using React DOM. To make sure that the behavior matches what happens in the browser, we’ll wrap the code rendering and updating it into ReactTestUtils.act() calls. The calls to act() will also flush the effects inside of them.

6. The useRef() Hooks behaves like instance variables

The “ref” object of useRef() hooks is a generic container whose current property is mutable and can hold any value, which is similar to an instance property of a class. We can write to it from inside useEffect

Example:

If we just wanted to set an interval, we wouldn’t need the ref ( id could be local to the effect), but it’s useful if we want to clear the interval from an event handler.

Example:

7. useMemo

React has a built-in hook called useMemo that allows us to memoize expensive functions so that we can avoid calling them on every render. We simply pass in a function and an array of inputs and useMemo will only recompute the memoized value when one of the inputs has changed.

Example:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

This returns a memoized value and passes a “create” function with an array of dependencies. This optimization helps to avoid expensive calculations on every render.

One simple reminder is that the function passed to useMemo runs during rendering. We can’t do anything there that we wouldn’t normally do while rendering.

For example, side effects belong in useEffect, not useMemo.

If no array is provided, a new value will be computed on every render.

8. Custom Hooks: Using a Custom Hook

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.

Example:
For example, useFriendStatus is a custom Hook:

We can now use the custom hook userFriendStatus, inside two different components, named FriendStatus and FriendListItem shown below -

Example:

Which is a lot clear and easy to understand code segment than to writing & struggling with these logics inside the components.

9. We Can Pass Information Between Hooks

As we know, Hooks are JavaScript functions, we can pass information between them.

In the example below, we’ve shown a chat message recipient picker that displays whether the currently selected friend is online or not.

Example:

The currently chosen friend ID is kept in the recipientID state variable, and it only updates when the user chooses a different friend in the <select> picker.

This lets us know whether the currently selected friend is online. If we pick a different friend and update the recipientID state variable, our useFriendStatus Hook will unsubscribe from the previously selected friend, and subscribe to the status of the newly selected one.

10. Caching methods: useCallback

useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

Example (without using useCallback):

function App() {
const [counter, setCounter] = useState(0);

function formatCounter(counterVal) {
return `The counter value is ${counterVal}`;
}

return (
<div className=”App”>
<div>{formatCounter(counter)}</div>
<button onClick={() => setCounter(prevState => ++prevState)}>
Increment
</button>
</div>
);
}

Every time the component re-renders, the following steps will happen -

  1. The useState() method will run and it will return the updated counter and the cached setCounter() method.
  2. Next, the formatCounter() function will be added to memory.
  3. Finally, some JSX is returned. The arrow function onClick() handler which is inside the <button/> will also be added into the memory.

This will slow down the rendering process. We need to either move the methods outside the component or cache the methods. To ignore all these things to be added into the memory, we can use the useCallback hook.

Example (using useCallback):

When this component re-renders, both onClick() and formatCounter() are not entered into memory again because useCallback will cache the onClick() method and formatCounter() has been moved outside the functional component. This will save us a lot of time during re-rendering.

import React, { useState, useCallback} from “react”;

function formatCounter(counterVal) {
return `The counter value is ${counterVal}`;
}
function App() {
const [counter, setCounter] = useState(0);

const onClick = useCallback(()=>{
setCounter(prevState => ++prevState)
},[]);

return (
<div className=”App”>
<div>{formatCounter(counter)}</div>
<button onClick={onClick}> Increment </button>
</div>
);
}

That’s all I’ve learned today about the React Hooks…Thanks for Reading. Happy Learning :)

--

--

Rahul Biswas

Love to work with Technologies, Web & obviously JavaScript.