React Hooks — (useState and useEffect-useRef with clean-ups)

CodeWithAL
6 min readSep 22, 2019

What are hooks?

I’m pretty sure you already heard about Hooks, since they have been around for a year or so, tho still so many people haven’t taken the time or gotten the chance to experiment with them yet. Here I will try to explain the concept through my understanding in this post.

But first things first, let’s quickly answer this question; Hooks are functions that let us “hook into” React state and lifecycle features from stateless functional(won’t anymore!) components. Hooks don’t work inside class based components — they allow us to use React without needing classes at ALL! The thing is that, they can only be used in functional components.

Why Hooks?

I can hear you asking, basically Hooks give us the possibility to extract stateful logic which before could only be used in Class components and allow us to use this logic in a separate and reusable way.

Let’s get started!

useState()

so Imagine having this presentational functional component and now we want to have a controlled input within the component. Normally this would be impossible with just a functional component but with Hooks we can create a controlled input by implementing theuseState Hook, which will store the current value entered in the input and will provide us with a function to update the state:

Basically, useState Hook always returns an array with 2 elements inside, first on as a pointer to yourstateand the second one as a state update functionsetState Below on the first snippet we see the not yet destructered syntax and on the second snippet we can see the destructered syntax, which is the official way to go and clearly, the readable way!

by passing an empty string as a parameter to our useState Hook we are simply initializing our variablevalue with an empty string. If we don’t pass an argument, it will initialize it with undefined we could have initialized it with an empty array or with null or whatever fulfilling our needs.

But wait, what if we want to control more than just one state in our functional component? Sure thing, we can. We can use as many Hooks as we want.

But It is important to note that there is one super important difference when you compare setState which you’re probably familiar from class based components to useState Hook. In class based components you always had to use an object as the state and whichever object you passed into the state was merged with the existing one but with useState you can even initialize with undefined or whatever you like and it doesn’t merge with the existing state, in fact it overrides whatever inside! So wee need follow a different protocol and use spread operator. Also I provided a with simple button to log the state into console.

Now there are two important rules when you work with hooks, with any hooks not only just with useState First, you must only use the Hooks in functional components or inside of other Custom Hooks. The second you should always use the hooks on the root level in your component. It means that you can’t use a hook in some nested function even if you’ve tried. The modern react projects have code checked you would have been warned! This also includes if statements, you can’t use a hook in an if statement block as well.

useEffect()

useEffect is a lifecycle Hook for functional components which basically combines componentDidMount, componentDidUpdate and componentWillUnmount. useEffect is also where you carry out your side effects as well.

Even though it is a lifecycle method like the others, in a way it’s better than the rest. The reason for it being better is that you can make use of useEffect multiple times within a single component, which allows you to split up and keep related logic grouped together while maintaining readability of your code.

I am going to use fetch to fetch data for simplicity, but it is up to you to use another data fetching library like axios. Then implement your useEffect hook for the data fetching:

useEffect is used to fetch data with fetch from the API and to set the data in the local state of the component with the useState Hook’s update(second argument) function. The promise resolving happens with async/await.

However, when you run your application, you should stumble into a nasty loop. useEffect hook runs when the component mounts but also when the component updates. Because setting the state after every data fetch, the component updates and useEffect runs again. It fetches the data again and again. That’s an infinite loop and it needs to be avoided. We only want to fetch data when the component mounts. That’s why providing an empty array as second argument(The second argument is an array with the dependencies of the function and only when such a dependency changes only then the function will rerun.) to the useEffect hook is vital to avoid activating it on component updates but only for the mounting of the component.

So this second argument is how to control, how often does the function runs by default for every render cycle. This can be changed. Here In the example actually there are no external dependencies(such as a variable or data to define the component outside of the useEffect — Yes setData is coming from outside and is external fundamentally but that’s an exception and it is a function generated by useState)

An empty array means this component runs only once after the first render acts like componentDidMount and never runs thereafter.

Now let’s go for an example built on top of our first examples with a dependency to show what’s really happening. Below what we are doing is simply every time that we are typing a character into our input field, by courtesy of passing enteredFilter as a dependency, useEffect callsfetchData function everytime enteredFilter is updated. Also below, I used a second useEffect Hook just to show that we can use as many of them as we want! (Of course we could have programatically sorted out the filter within our state and by not calling the API everytime but, it’s purely for demonstrational purpose!)

Incorporating useRef with useEffect and cleanups

Basically, the useRef Hook is a function that returns a mutable ref object whose .current property is initialized to the passed argument (initialValue)

If you check out your network tab from google chrome developers tools you will see that we are having an issue, we’re sending a request for every keystroke we press on and basically we’re spamming the servers with requests.

So would probably be better if we set some timer and only when the timer expires we check for the current input to see if it is the same as at the beginning of the timer and only then we fetch from our servers to prevent unnecessary network requests.

How can we fix that. For that it’s important to understand how closures work in JavaScript. Entered filter here will actually be locked in when we set the timer. So entered filter here will not be the current value the user enters. It will be the old value 500ms ago when useEffect is executed. And there only after 500ms they will be executed. The code below will help you understand no worries!

Still we have two problems tho, first our initial render happens after 500ms, this may look ok when we just check out the initially rendered page just because 500ms is negligible in terms of fetching and rendering data but if we just make it like 5000ms we we would have found ourselves waiting for data to render, a lot!

Second, we set a new timer whenever the effect runs into effect. Still runs in the end whenever our input changes so we’re setting a bunch of timers which are all managed Instead of setting a timer for every effect therefore having multiple timer is in the end for every keystroke we want to make sure we always cleared the previous timer because it doesn’t matter to us anymore if there is a new keystroke the old timer can be dismissed.

useEffect basically runs after every render cycle and it can also return something; another function(an anonymous arrow function used for the example below) The code in that function will now execute right before useEffect will run the next time, it is a cleanup function that basically runs once useEffect is done and before it runs again.

Thanks for reading, I hope that you enjoyed the read and maybe even learned a few things out of it. See you next time…

--

--