React's Hooks useState and useEffect
Tags: react, javascript, node, webdev
Published: 2023-07-02 05:44:04

Hooks were first introduced in version 16.8 of React, and they have revolutionized the way we write React code. With Hooks, you can easily extract stateful logic from functional components, making it possible to reuse and test it independently.

React developers should have a strong grasp of two critical Hooks: useState and useEffect. These Hooks are essential for managing state and performing side effects in functional components. In this blog post, we will explore the useState and useEffect hooks, their usage, and how they simplify React development.

#useState Hook#

When working with React applications, managing state can be done using either class components or the useState hook. While both options serve the same purpose, there are variations in syntax, lifecycle methods, and code organization that set them apart.

Example of a counter using a class component:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8kfdfitngs2kedfb3ux.png)

Now, let’s look at doing the same thing with the React useState Hook, you can easily incorporate a state in a functional component. This hook provides an array consisting of two elements - the current state value and a function that can be used to update the state.

Example of a counter using the useState hook:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tq93grxen23n1cgc3y8y.png)

To implement the functionality, the initial step is to import the useState Hook from React. Then, within the Counter function, we need to invoke the useState Hook. This will provide us with the current state and the corresponding function that modifies it, as demonstrated in the example with count and *setCount*.

It's important to keep in mind that variables typically disappear upon exiting a function. However, React is unique in that it preserves state variables, including the count variable.

With the useState Hook, you have the ability to declare state variables of any type. Additionally, this Hook can be utilized multiple times within a single component.

#useEffect Hook#

React's useEffect hook is a powerful feature that allows you to handle side effects in functional components. Side effects are tasks that are executed outside the scope of the component's rendering, such as data fetching, subscribing to events, or interacting with the browser's DOM. The useEffect hook replaces the lifecycle methods in class components and provides a clean and declarative way to manage side effects in React applications.

Here's an example that demonstrates the usage of useEffect:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvuazfvaxkp8x4slqrup.png)

In the previous example, a timer is initiated using the useEffect hook to increment the seconds state every second. To ensure that the effect runs only once upon component mount, an empty dependency array [] is passed as the second argument.

The function passed to useEffect can contain any code that should be executed as a side effect, such as data fetching, API calls, subscribing to events, or modifying the DOM. The cleanup function, if provided, is returned from the effect function and will be called when the component unmounts or when the dependencies change.

React components can have two types of side effects: ones that require cleanup and ones that do not. In the previous example, no cleanup was necessary. However, setting up a subscription, closing a socket, and clearing timers are a few examples of side effects that do require cleanup.

**useEffect with cleanup**

The cleanup function within useEffect plays a crucial role in releasing resources, preventing memory leaks, avoiding unexpected behavior, maintaining a clean state, and optimizing resource utilization. By managing side effects properly, it helps to ensure that your React components perform well, are predictable, and resilient.

Optional cleanup functions are available to clean up any resources or subscriptions that may have been created by the effectful function. These functions are executed either when the component is unmounted or when the dependencies of the useEffect hook change.

Here's an example of using useEffect with cleanup:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tgfs2hhnyo1hnyhvzhuw.png)

Our program utilizes a state variable, "count," which initializes at 0 and increments every second through the use of setInterval. Within the effect function, we establish the interval via setInterval and assign its reference to the "interval" variable. The cleanup function is then returned from the effect function, which clears the interval using clearInterval and logs a console message. As the dependency array is empty ([]), the effect will only run once after the initial render.

Once the component is mounted, the effect function runs and sets up the interval. Every second, the setInterval function increases the count state variable. The component then re-renders with the latest count value.

When the component is unmounted or if any dependencies change, the cleanup function is activated. This function uses clearInterval to stop the interval and prevent it from incrementing the count. Moreover, it writes the message "Interval cleared" to the console. By utilizing clearInterval in the cleanup function, we can guarantee that the interval is correctly cleared and won't continue to run when the component is not in use. This prevents memory leaks and ensures that the component functions correctly.

**Empty Dependency Array** 

To pass an empty array of dependencies as the second argument, we can do it in this way:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/shfllpnp8s1ptr6osats.png)

If you use an empty dependency array ([]) as the second argument with the useEffect hook, it indicates that the effect should only run once during the initial rendering of the component. This approach guarantees that the effect is not reliant on any particular values or state variables, and as such, it won't need to be re-executed if any dependencies change.

Here's an example of fetching data from an API using useEffect:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ptda22pwtsva6nupqux.png)

To store the data retrieved from the API, we utilize the useState function to create a state variable named "data". We make use of the useEffect hook, which is passed an empty dependency array ([]) as its second argument, to retrieve data from the API via axios.get. This guarantees that the effect runs only once during the component's initial rendering. Using setData, we store the fetched data in the "data" state variable. Finally, we map and display the names of the items in the JSX.

To ensure that the useEffect hook runs only once when the component is mounted, you can provide an empty dependency array. This hook fetches data from the API and updates the data state variable. As a result, the effect will not be triggered again during subsequent re-renders of the component. This prevents unnecessary API calls and ensures that the data is fetched only once.

In summary, React functional components have been transformed by the introduction of useState and useEffect hooks. These hooks offer a simpler and more effective way to manage state and handle side effects, resulting in cleaner and easier-to-maintain code. By gaining a thorough understanding of these hooks, developers can effortlessly create highly interactive and efficient React applications.