A Practical Overview on React Hooks

State and other React capabilities can now be used in functional components in addition to merely class components thanks to React hooks.

In this article, we aimed at providing an overview of some React Hooks, benefits of using them while building your applications and advanced Hooks you can leverage on.

By doing away with the requirement for class components and the corresponding lifecycle functions, they enable you to write shorter, simpler code. UseState, UseEffect, and UseRef are a few hook examples. You may manage the states, side effects, and context of your functional components with these hooks.

The following part will provide a brief comparison between class and functional components in React. You can use class components or functional components to build apps using React.

The React.Component basic class is extended by classes in JavaScript called class components. They have access to the more complexly structured lifecycle methods componentDidMount and componentDidUpdate.

On the other hand, functional components are JavaScript functions that accept props as an input and produce JSX (a JavaScript syntax extension). They have a simplified structure and no access to lifecycle methods. Since functional components don't have instances, the "this" keyword is not necessary.

To put it simply, class components are more complex but have more features.

Since we have already seen similarities between class and functional components, let's look at the advantages of using hooks. Use React hooks while creating apps for a variety of reasons, including:

Hooks allow you to reuse functionality across several components, which organizes your code and makes it simpler to maintain.

Hooks make it possible to write simpler, more readable code by doing away with the requirement for classes.

To go deeper, we will be looking at some of the React Hooks we can use when building our apps in the next section

The useEffect Hook

useEffect is a hook that lets you synchronize a component with an external system. It is used for side effects, such as fetching data from an API, updating the document title, or setting up a subscription.

Here is an example of how to use useEffect to fetch data from an API in a functional component:

import { useState, useEffect } from 'react';

function MyComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {
    fetch('https://my-api.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return (
    <div>
      {data.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
}

In this example, the useEffect the hook is used to fetch data from an API when the component is rendered. The first argument of the useEffect function is a callback that contains the logic to fetch the data, and the second argument is a list of dependencies, in this case is an empty array which means the effect should only run once when the component is rendered and not re-run when the component updates.

In simple terms, useEffect allows you to run some code after the component is rendered and it's used to handle side effects like fetching data, updating the title, etc. and it's passed with a callback function that contains the logic to handle the side effect and a list of dependencies to decide when the effect should re-run.

In the example above, we use the useState hook. We will be looking into what it is in the next section to help make it clearer.

The useState Hook

useState is a hook that allows you to add state to a functional component. It is used to store and update data that affects the component's behavior or appearance.

Here is an example of how to use useState to keep track of a counter in a functional component:

import { useState } from 'react';

function MyCounter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example, the useState hook is used to set the initial value of the count variable to 0, and the setCount function is used to update the value of count when the button is clicked.

In simple terms, useState allows you to add state to a functional component, it returns an array with two values, the first is the current state, and the second is a function to update the state.

The useRef Hook

useRef is a hook that allows you to create a reference to a DOM element or a JavaScript object in a functional component. It is used to store and access a value that does not change during the component's lifecycle.

Here is an example of how to use useRef to create a reference to an input element in a functional component:

import { useRef } from 'react';

function MyForm() {
  const inputRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    console.log(inputRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={inputRef} />
      <button type="submit">Submit</button>
    </form>
  );
}

In this example, the useRef hook is used to create a reference to the input element, and the ref attribute is used to attach the reference to the element. When the form is submitted, the handleSubmit function will log the value of the input by accessing it through the current property of the inputRef reference.

In simple terms, useRef allows you to create a reference to a DOM element or a JavaScript object in a functional component, it returns a plain JavaScript object with a current property and you can store a value that does not change during the component's lifecycle, in the current property.

There are advanced hooks in React which we are going to have a quick glance at in the next section

Advanced Hooks in React

Advanced React Hooks are hooks that provide more specialized functionality beyond state and side-effects. Some examples of advanced hooks are useReducer, useMemo, and useCallback.

useReducer is a hook that allows you to handle complex state changes in a functional component. It can be used as an alternative to useState when the state updates depend on the previous state. Here's an example of how to use useReducer to handle a counter:

import { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function MyCounter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>You clicked {state.count} times</p>
      <button onClick={() => dispatch({ type: 'increment' })}>
        Increment
      </button>
      <button onClick={() => dispatch({ type: 'decrement' })}>
        Decrement
      </button>
    </div>
  );
}

useMemo is a hook that allows you to memoize a value, so it is only recomputed when one of its dependencies changes. This can be useful for optimizing the performance of expensive calculations. Here's an example of how to use useMemo to memoize the result of a calculation:

import { useMemo } from 'react';

function MyComponent({ a, b }) {
  const memoizedValue = useMemo(() => expensiveCalculation(a, b), [a, b]);

  return <div>{memoizedValue}</div>;
}

useCallback is a hook that allows you to create a callback that is only recreated when one of its dependencies changes. This can be useful for optimizing the performance of passing down callbacks to child components. Here's an example of how to use useCallback to create a callback:

import { useCallback } from 'react';

function MyComponent({ onClick }) {
  const memoizedCallback = useCallback(() => {
    console.log('Clicked!');
  }, []);

  return <button onClick={memoizedCallback}>Click me</button>;
}

When using advanced hooks, it's important to note that they should only be used when they are necessary and when they provide a real benefit. They can make your code more complex, and harder to understand and test. Therefore, it's best to use them in combination with simple hooks and only when they provide a real performance benefit.

Conclusion

This was a simple overview of React Hooks, their benefits, and a quick glance at how they can be used to improve our apps while building. We saw that they can be used to make our code more readable, reusable and increase the performance of our apps.