Introduction

React Hooks, introduced in React 16.8, have revolutionized how developers handle state and side effects in functional components. Prior to hooks, functional components were limited to stateless logic, necessitating class components for dynamic behaviour. Hooks enable state management and other React features within functional components, resulting in cleaner, more concise, and maintainable code. One can join the Best React JS Course to learn more about the different React Hooks and their utilities. By providing a structured approach to organizing component logic and facilitating code reuse, hooks have significantly enhanced the efficiency and readability of React applications, marking a pivotal shift in React’s development paradigm.

All About React Hooks

React Hooks, introduced in React 16.8, are a significant advancement in the React library that allows developers to use state and other React features without writing a class. They offer a simpler and more intuitive approach to managing state and side effects in functional components, which previously required cumbersome class components. This change has streamlined the development process, making code more readable, maintainable, and easier to test.

The Need for Hooks

Before Hooks, functional components were limited in functionality. They were stateless and could not manage side effects like fetching data, subscribing to services, or manipulating the DOM. Class components were necessary for these tasks but introduced complexity with lifecycle methods and this keyword, often leading to confusing and error-prone code.

Basic Hooks

React provides several built-in hooks, each serving a specific purpose. The most commonly used hooks include:

1.    useState

The useState hook is used to add state to functional components. It returns an array with two elements: the current state value and a function to update that state.

“import React, { useState } from ‘react’;

 

function Counter() {

  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, useState initializes count to 0. The setCount function updates the state whenever the button is clicked, re-rendering the component with the new state.

 

2.    useEffect

The useEffect hook handles side effects in functional components, such as data fetching, subscriptions, and manually changing the DOM. It runs after the first render and after every update.

“import React, { useState, useEffect } from ‘react’;

 

function DataFetcher() {

  const [data, setData] = useState(null);

 

  useEffect(() => {

    fetch(‘https://api.example.com/data’)

      .then(response => response.json())

      .then(data => setData(data));

  }, []);

 

  return (

    <div>

      <pre>{JSON.stringify(data, null, 2)}</pre>

    </div>

  );

}”

The empty array [] as the second argument to useEffect ensures it only runs once after the initial render, similar to componentDidMount in class components.

 

3.    useContext

The useContext hook provides a way to pass data through the component tree without manually passing props down at every level.

“import React, { useContext } from ‘react’;

 

const MyContext = React.createContext();

 

function Display() {

  const value = useContext(MyContext);

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

}

 

function App() {

  return (

    <MyContext.Provider value=”Hello, World!”>

      <Display />

    </MyContext.Provider>

  );

}”

useContext allows the Display component to access the value provided by MyContext.Provider without passing props.

Advanced Hooks

React also provides several more advanced hooks for handling more complex scenarios:

1.    useReducer

The useReducer hook is suitable for managing more complex state logic that involves multiple sub-values or when the next state depends on the previous one.

“import React, { useReducer } from ‘react’;

 

const initialState = { count: 0 };

 

function reducer(state, action) {

  switch (action.type) {

    case ‘increment’:

      return { count: state.count + 1 };

    case ‘decrement’:

      return { count: state.count – 1 };

    default:

      throw new Error();

  }

}

 

function Counter() {

  const [state, dispatch] = useReducer(reducer, initialState);

 

  return (

    <div>

      <p>Count: {state.count}</p>

      <button onClick={() => dispatch({ type: ‘increment’ })}>+</button>

      <button onClick={() => dispatch({ type: ‘decrement’ })}>-</button>

    </div>

  );

}”

 

2.    useCallback and useMemo

The useCallback hook memoizes callback functions, which can improve performance by preventing unnecessary re-renders.

“import React, { useState, useCallback } from ‘react’;

 

function Parent() {

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

  const increment = useCallback(() => setCount(count + 1), [count]);

 

  return <Child increment={increment} />;

}

 

function Child({ increment }) {

  return <button onClick={increment}>Increment</button>;

}”

The useMemo hook memoizes values to avoid expensive calculations on every render.

“import React, { useMemo } from ‘react’;

 

function ExpensiveComponent({ a, b }) {

  const result = useMemo(() => expensiveCalculation(a, b), [a, b]);

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

}”

 

Custom Hooks

Developers can create custom hooks to encapsulate and reuse logic across multiple components. A custom hook is simply a JavaScript function that calls other hooks.

“import { useState, useEffect } from ‘react’;

 

function useFetch(url) {

  const [data, setData] = useState(null);

 

  useEffect(() => {

    fetch(url)

      .then(response => response.json())

      .then(data => setData(data));

  }, [url]);

 

  return data;

}

 

// Usage

function MyComponent() {

  const data = useFetch(‘https://api.example.com/data’);

  return <div>{JSON.stringify(data, null, 2)}</div>;

}”

 

Benefits Of Hooks

  • Simplicity: Hooks eliminate the need for complex class components and lifecycle methods, making code more straightforward.
  • Reusability: Custom hooks allow the reuse of stateful logic across different components.
  • Readability: Functional components with hooks are often easier to read and understand.
  • Testing: Hooks simplifies testing by decoupling logic from the UI components.

Conclusion

React Hooks have transformed the landscape of React development by simplifying the management of state and side effects in functional components. They enable cleaner, more reusable, and more maintainable code, allowing developers to create robust applications with less boilerplate. The React JS Interview Questions often involve questions on React Hooks, making them an integral part of the React training. With hooks, React embraces a more functional approach to component design, streamlining both the development process and the end-user experience.