DEV Community

Cover image for Ins & Outs of Two React Hooks: useState and useEffect
Damla Erkiner
Damla Erkiner

Posted on

Ins & Outs of Two React Hooks: useState and useEffect

These days, React is one of the most popular front-end development libraries out there. Many companies are looking for talented React developers to add to their teams.

There are of course other tools like Angular and Vue. But React is often considered more beginner-friendly compared to these.

So if you have some intermediate knowledge of HTML5, CSS3, and JavaScript, you can dive right in and start learning React. With some practice and project development, you can be a pro in no time.

React Functional Components vs Class Components

React uses reusable and maintainable components to provide a solid user experience. And you can choose to work either with 'Class Components' or 'Functional Components'. Their syntax differs a bit as you can see in the code samples below:

Example of a class component:

class Sample extends React.Component {
    render() {
        return <h1>This is a Class Component Sample. <h1/>
     }
   }
Enter fullscreen mode Exit fullscreen mode

Example of a functional component:

function Sample(props) {
    return <h1> This is a Functional Component Sample. <h1/>
  }
Enter fullscreen mode Exit fullscreen mode

Functional Components and React Hooks

With React version 16.8, developers no longer had to use class components because React introduced hooks. This lets you write your code through functions.

Even though you still use class components in React, functional components have become more and more popular. This is because you can use hooks in functions easily and it improves performance. The React docs even encourage developers to use functional components in lieu of class components in its official documentation.

Now that you know class components are no longer really needed, we had better learn how hooks work in general so you can start using them in your own code.

Here, we'll specifically focus on the useState and useEffect hooks rather than all the others (just keep in mind that there are others).

React Lifecycles and Hooks

Before we begin, let's get a grip on some important concepts. In React, every component is associated with a lifecycle which has the following steps:

  1. Mounting
  2. Updating
  3. Unmounting

What does that mean? Well, in a way, each component is like a living organism. It is born (mounting), lives (updating), and eventually dies (unmounting).

Image description

React hooks help us utilise some React functionalities like state along with lifecycle techniques.

As far as hooks are concerned, there are some significant rules to be aware of. In React, hooks:

  • must be imported from the 'React' library for each component.

  • should only be called at the beginning of a component.

  • can only be used inside functions.

  • cannot be turned into conditionals.

  • cannot be used with class components.

Now that you know the basics, let's dive into the two hooks we're going to cover in this tutorial.

How to Use the useState Hook in React

The useState hook is the one that helps us monitor state in our components. But what exactly do we mean by state?

Well, state can be some data, for instance. Perhaps, it is better to examine the state hook with some examples to put it in context.

First and foremost, we must call our state hook at the top of our component file. In other words, we simply destructure it from the 'react' library. The syntax is as follows:

import { useState } from 'react';
Enter fullscreen mode Exit fullscreen mode

The second thing you need to know about useState is that it has an initial state and it returns the current state and a function altering that state. Let's see what I mean by that:

import { useState } from 'react';

function CoolPlace() {
    const [place, setPlace] = useState("");
}
Enter fullscreen mode Exit fullscreen mode

In the above example, the word 'place' stands for our present state and the expression 'setPlace' is the one that is about to modify our current state.

Now that those are variables, you can of course pick whatever you want to use as names. But the general practice is to go for meaningful names that can remind you what to do in the next phase of your project.

Here, the initial value is set to an empty string: useState(" "), but that can be an empty array or something else depending on what you're planning to do with your state. It all depends on your project.

Let's now integrate a button to alter our current state with a click.

import { useState } from 'react';
import ReactDOM from 'react-dom/client';


function CoolPlace() {
    const [place, setPlace] = useState("Sydney");

    return (
        <>
        <p> {place} is a gorgeous city.<p>
        <button 
        type="button" 
        onClick={() => setPlace("Rotterdam"}
        >Choose a Place</button>
        </>     
     )  
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<CoolPlace />);


RESULT:
 (Before hitting the button): Sydney is a gorgeous city
 (After hitting the button) : Rotterdam is a gorgeous city.
Enter fullscreen mode Exit fullscreen mode

This time, the initial state is set to 'Sydney', not an empty string. With the above button named as 'Choose a Place', you may change your new state to 'Rotterdam' because we set the place to a new city through our onClick set-up inside the button.

With the useState hook, we can track numbers, arrays, booleans, strings and so on. It's also possible to use more than one state in a function. We can simultaneously benefit from the destructuring method to come up with dynamic values.

If you examine the following example, you'll see how practical this situation is for developers:

import { useState } from "react";
import ReactDOM from "react-dom/client";

function OnlineStore() {
  const [platform, setPlatform] = useState("shopify");
  const [products, setProducts] = useState("clothes");
  const [payment, setPayment] = useState("PayPal");

  return (
    <>
      <p> The platform for our online store is {platform}.</p>
      <p> We will sell {products} there.</p>
      <p> The payment will be made through {payment}.</p>

    </>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);


RESULT:
The platform for our online store is shopify.
We will sell clothes there.
The payment will be made through PayPal.
Enter fullscreen mode Exit fullscreen mode

Let's now take a look at the useState hook in a different example. This time, let's see how we can use it with an object:

import { useState } from "react";
import ReactDOM from "react-dom/client";

function Dog() {
  const [dog, setDog] = useState({
    breed: "Bulldog",
    traits: "dependable and predictable",
    lifespan: "8-10 years",
    color: "brown"
  });

  return (
    <>
      <h1> {dog.breed}</h1>
      <p>
        This beautiful animal's color is {dog.color}. It is a {dog.traits} creature, but its lifespan is only {dog.lifespan}.
      </p>
    </>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Dog />);


RESULT:
Bulldog
This beautiful animal's color is brown. It is a dependable and predictable creature, but its lifespan is only 8-10 years.
Enter fullscreen mode Exit fullscreen mode

How to Update State in React with useState
Thanks to the JavaScript spread operator, we are able to update only certain properties in an object or an array.
Let's take a look at an example to see how this works and why it's so practical:

import { useState } from "react";
import ReactDOM from "react-dom/client";

function Sport () {
  const [sport, setSport] = useState({
    type: "soccer", 
    numberOfPlayers: 11, 
    firstPlayed: "the Mid-19th century", 
    popularIn: "Brazil"
  });

  const changeSport = () => {
    setSport (previousState => {
      return { ...previousState, popularIn: "Germany" }
    });
  }

  return (
    <>
      <h1>{sport.type}</h1>
      <p>
        In this sport, there are {sport.numberOfPlayers} players. It was first played in {sport.firstPlayed}. Everyone likes it in {sport.popularIn}.
      </p>
      <button
        type="button"
        onClick={changeSport}
      >Blue</button>
    </>
  )
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Sport />);



RESULT:
(Before hitting the button):
Soccer
In this sport, there are 11 players. It was first played in the Mid-19th century. Everyone likes it in Brazil. 

(After hitting the button):
Soccer
In this sport, there are 11 players. It was first played in the Mid-19th century. Everyone likes it in Germany. 
Enter fullscreen mode Exit fullscreen mode

In the above arrangement, we have an object inside the useState hook. The function is about sports in general, but the useState hook is not an empty object this time and it shows the properties of a specific sport (soccer).

Suppose we want to keep all the properties of that object, except the 'popularIn' property. We can easily do that by keeping all the other properties via the spread operator as you can see in the example.

If you don't know how that operator functions, you should check out this article because it is crucial not only in JavaScript but also in React.

Thanks to this set up, once you hit the button, it will just change only a specific property and the country will be Germany instead of Brazil (but all the other properties will be preserved).

How to Use the useEffect Hook in React

The second hook that we're going to analyse is called useEffect. Just like its name suggests, it is in fact a kind of side effect. No worries though. This is not like the bad side effects you might be thinking about...

Image description

The actions handled by this hook include updating the DOM and fetching data.

We must be cautious when utilising the useEffect hook, though. Here is the problem: if there are no dependencies in it as seen in the following scenario, it leads to an infinite loop and we definitely don't want that. That way, it operates on every render.

useEffect(() => {

});
Enter fullscreen mode Exit fullscreen mode

So how can we integrate some dependencies in the useEffect hook? Well, we can stop that infinite loop if we add an empty array at the end of it as you see down below. Don't forget to use a comma before the array, though. Missing punctuation marks will break your code.

useEffect(() => {

},[]);
Enter fullscreen mode Exit fullscreen mode

The 'useEffect' hook accepts two different arguments, but it is always better to put it into context to grasp it fully.

Let's look at a specific example so we can see our two hooks, 'useState' and 'useEffect' in action:

function FetchRestaurants() {
  const [restaurants, setRestaurants] = useState([]);


  useEffect(() => {
    async function fetchRestaurants() {
      const response = await fetch('./data');
      const newData = await response.json(response);
      setRestaurants(newData);
    }
    fetchRestaurants();
  }, []);


  return (
    <div>
      {restaurants.map(name => <div>{name}</div>)}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Let's assume that we've got a JSON API data file that has a list of restaurants with their properties. We try to fetch that list by using not only the useEffect hook, but also the useState hook by benefitting from the async and await functions.

In the first place, useState is set to an empty array. The reason is that we're planning to benefit from useEffect along the way.

Once we utilise async and await inside the useEffect hook, we get the data by locking the related list in the previously-created empty array. Actually, this is generally the custom set-up when fetching data.

As a side effect, the useEffect hook will render the list of the restaurants. But this will not lead to an infinite loop because there is again another empty array before the hook ends. As soon as the job is done, it will stop re-rendering with this arrangement.

Wrapping Up

As you see, the useState and useEffect hooks are extremely important if you're using functional programming in React. It's also recommended to use hooks instead of class components.

Image description

One of the best ways to practise is to get your hands dirty and start writing your own code. You can start by playing around with the above examples and try to come up with your own versions. Once you feel comfortable with them, you can then use them in a more complex project.

Happy coding!

โ€œKnowledge is power.โ€ โ€“ Francis Bacon

Top comments (1)

Collapse
 
balajin96 profile image
balaji

good content