React Hooks Tutorial for Beginners: Learn useEffect Hook

If you are a React developer, and haven’t learned about React hooks yet, it is the perfect time to start learning now. In this post, we are specifically going to learn about the React Hook, the useEffect.

In this article, let’s dive in and get started with the next hook, _useEffect. _This article assumes that you have already learned about the _useState _hook.

Note: If you are new to React, I would recommend learning Hooks first, and then learn older way of doing things.

React Hooks – What is it trying to solve?

Hooks were introduced in React version 16.8 and now used by many teams that use React.

Hooks solves the problem of code reuse across components. They are written without classes. This does not mean that React is getting rid of classes, but hooks is just an alternate approach.

In React, you can soon end up with complex components with stateful logic. It is not easy to break these components because within the class you are dependent on the React Lifecycle Methods. That’s where React Hooks come in handy. They provide you a way to split a component, into smaller functions. Instead of splitting code based on the Lifecycle methods, you can now organize and split your code into smaller units based on functionality.

This is a huge win for React developers. We have always been trained to write React classes which adhere to the confusing lifecycle methods. Things are going to get better with the introduction of hooks to React.

‘Hooks are functions that let you “hook into” React state and lifecycle features from function component. They do not work within a class. They let you use React without a class.’ – React Official Blog post.

How to use _useEffect _hook?

_useEffect _hook essentially is to allow side effects within the functional component. In class components, you may be familiar with lifecycle methods. The lifecycle methods, _componentDidMount, componentDidUpdate _and componentWillUnmount, are all all handled by the useEffect hook in functional components.

Before the introduction of this hook, there was no way to perform these side-effects in a functional component. Now the useEffect hook, can provide the same functionality as the three lifecycle methods mentioned above. Let’s look at some examples to learn this better.

Before Hooks

import React from "react";

class TraditionalComponent extends React.Component {
  state = {
    buttonPressed: "",
  };

  componentDidMount() {
    console.log("Component did mount", this.state.buttonPressed)
  }

  componentDidUpdate() {
    console.log("Component did update", this.state.buttonPressed)
  }

  onYesPress() {
    this.setState({ buttonPressed: "Yes" });
  }

  onNoPress() {
    this.setState({ buttonPressed: "No" });
  }

render() {
    return (
      <div>
        <button onClick={() => this.onYesPress()}>Yes</button>
        <button onClick={() => this.onNoPress()}>No</button>
      </div>
    );
  }
}

export default TraditionalComponent;

In the example above we have coded a traditional class React component. In class components, we have access to the lifecycle methods. Here I am using _componentDidMount() _and _componentDidUpdate() _with console logs in each of them. When you run this above code, and look at the console you will initially see the following message:

Component did mount ""

_**componentDidMount() **_is called as soon as the component is mounted and ready. This is a good place to initiate API calls, if you need to load data from a remote endpoint.

Now if we press the Yes button or the _No _button, the button state is updated. At this point you should see the following on the console:

Component did update Yes 
Component did update Yes 

The _componentDidUpdate()_method is called when the state changes. This lifecycle method is invoked as soon as the updating happens. The most common use case for the _componentDidUpdate() _method is updating the DOM in response to state changes.

Alright, now what does the _useEffect _hook really do?

Functional Component with useEffect Hook

Let’s now re-write our example into a functional component.

import React, { useState, useEffect } from "react";

const UseEffectExample = () => {
  const [button, setButton] = useState("");

  //useEffect hook
  useEffect(() => {
    console.log("useEffect has been called!", button);
  });

  const onYesPress = () => {
    setButton("Yes");
  };

  const onNoPress = () => {
    setButton("No");
  };

return (
      <div>
        <button onClick={() => this.onYesPress()}>Yes</button>
        <button onClick={() => this.onNoPress()}>No</button>
      </div>
    );
};

export default UseEffectExample;

We have now rewritten our class component into a functional component.

Note: The first thing we need to do to get the useEffect to work is, import the _useEffect _from React.

import React, { useEffect } from "react";

Notice here that the useEffect hook has access to the state. When you run this code, you will initially see that the useEffect is called which could be similar to the componentDidMount. After that every time the state of the button changes, the useEffect hook is called. This is similar to the componentDidUpdate lifecycle.

// Console
useEffect has been called! ""    // comparable to componentDidMount
useEffect has been called! Yes  // comparable to componentDidUpdate
useEffect has been called! No  // comparable to componentDidUpdate

I hope you are with me so far. Let’s look into some more details about the _useEffect _hook.

Passing Empty Array to useEffect Hook

You can optionally pass an empty array to the useEffect hook, which will tell React to run the effect only when the component mounts.

Here is the modified useEffect hook from the previous example, which will occur at mount time.

//useEffect hook
  useEffect(() => {
    console.log("useEffect has been called!", button);
  }, []); 

When you run this on the console you will only see the _useEffect _being called once at mount.

// Console
useEffect has been called! ""    // comparable to componentDidMount

Separate Concerns using Multiple useEffect Hooks

An interesting feature of the _useEffect _hook is that, you can separate them into multiple hooks, based on the logic. With lifecycle methods, this was not possible. Often, unrelated logic was combined within the same lifecycle method, because there could only be one of each lifecycle method within the class component.

If you have multiple states in your functional component, you can have multiple _useEffect _hooks. Let’s extend the previous example, by adding another state within the component, that display the titles of blog posts. Now this is unrelated to the yes and no button we had. We can create multiple useEffect hooks, to separate the concerns as shown below:

import React, { useState, useEffect } from "react";
import { default as UUID } from "uuid";

const UseEffectExample = () => {
  const [button, setButton] = useState("");

  const [blogPosts, setBlogPosts] = useState([
    { title: "Learn useState Hook", id: 1 },
    { title: "Learn useEffect Hook", id: 2 }
  ]);

  useEffect(() => {
    console.log("useEffect has been called!", button);
  }, [button]);

  useEffect(() => {
    console.log("useEffect has been called!", blogPosts);
  }, [blogPosts]);

  const onYesPress = () => {
    setButton("Yes");
  };

  const onNoPress = () => {
    setButton("No");
  };

  const onAddPosts = () => {
    setBlogPosts([...blogPosts, { title: "My new post", id: UUID.v4() }]);
  };

  return (
    <div>
        <button onClick={() => this.onYesPress()}>Yes</button>
        <button onClick={() => this.onNoPress()}>No</button>
      <ul>
        {blogPosts.map(blogPost => {
          return <li key={blogPost.id}>{blogPost.title}</li>;
        })}
      </ul>
      <button onClick={() => onAddPosts()}>Add Posts</button>
    </div>
  );
};

export default UseEffectExample;

In the example above, we have a button state and a blog post state within the component. We have separated the unrelated logic into two different effect hooks. With the lifecycle methods, this would have not been possible. Hooks let us split the code based on what it is doing rather than a lifecycle method name. React will apply every effect used by the component, in the order they were specified.

When we run this code, when the component is mounted both the useEffect hooks are run as follows:

Learn useEffect Hook in React

You can see how the effects have been separated for each state. This is done by passing the state within an array to the _useEffect _hook.

Now if the Yes/No button is pressed, you should see this on the console.

Learn useEffect Hook in React

Notice here, that the useEffect for the blogPosts has not been invoked here. This tells React which effect to apply, without bundling them all within a call. Now if we clicked on adding a blog post button, we would see its effect take place.

Learn useEffect Hook in React

You get the idea!

Optimization ?

If you have you are used to the class components with lifecycle methods, you would have tried to optimize when the _componentDidUpdate _is called by passing the _prevProps _or _prevState _and compare it with the current state. Only if they don’t match the componentDidUpdate will happen. Now with _useEffect _hook, you can achieve the same optimization by simply passing the state in an array as a parameter as we have seen in the example above. This will ensure that the hook is run when the state passed to the effect changes.

Conclusion

Congratulations, you have stayed with me so far! Hooks is a fairly newer concept in React, and the official React documentation does not recommend that you rewrite all your components using Hooks. Instead, you can start writing your newer components using Hooks.

If you want to play with the code samples I used in this blog post, they are available on my GitHub Repo below:

React Hooks Examples

#reactjs #react #reach-hooks #hooks #webdev

React Hooks Tutorial for Beginners: Learn useEffect Hook
22.25 GEEK