Contents

Hooks in React

React Hooks were introduced in React 16.8 to allow function components to use state and other features that were previously only available in class components. Hooks provide a way to manage state, handle side effects, and reuse logic without writing class components. They enable a cleaner and more functional approach to developing React applications.

Introduction to React Hooks

Before Hooks, if you wanted to manage state or lifecycle methods, you had to use class components. Class components often led to verbose and complex code, especially with lifecycle methods like componentDidMount and componentDidUpdate. Hooks were introduced to solve this by allowing developers to use state and other features within function components.

Why Hooks?
  • Simpler code: Hooks reduce the need for complex class components, making code easier to read and write.
  • Reusable logic: Hooks allow you to extract and reuse logic in the form of custom hooks.
  • No this keyword: Since hooks are used in function components, there’s no need to manage this, which is a common source of confusion in class components.
  • Better separation of concerns: Hooks help separate stateful logic from UI logic, improving code organization.

 

Common Hooks:

  1. useState: For managing state in function components.
  2. useEffect: For performing side effects in function components.
  3. useContext: For accessing context in function components.
  4. useReducer: For managing complex state logic.
  5. useCallback, useMemo, useRef: For optimizing performance and managing refs.

Using useState and useEffect Hooks

useState Hook

The useState hook allows you to add state to function components. It returns an array with two elements: the current state value and a function to update it.

Example:

				
					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>
  );
}

export default Counter;


				
			

In this example:

  • count is the state variable, and its initial value is set to 0.
  • setCount is the function used to update count.
  • Clicking the button updates the state using setCount, and the component re-renders with the new state.

 

useEffect Hook

The useEffect hook lets you perform side effects in function components. It combines the capabilities of componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle methods in class components.

Example:

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

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

export default Counter;


				
			

In this example:

  • count is the state variable, and its initial value is set to 0.
  • setCount is the function used to update count.
  • Clicking the button updates the state using setCount, and the component re-renders with the new state.

Custom Hooks and Rules of Hooks

Custom Hooks

Custom hooks allow you to encapsulate and reuse stateful logic across multiple components. A custom hook is simply a JavaScript function whose name starts with use and that calls other hooks.

Example: Custom Hook for Window Width
				
					import { useState, useEffect } from "react";

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth);
    };

    window.addEventListener("resize", handleResize);

    // Cleanup function
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return width;
}

export default useWindowWidth;

				
			

You can now use the useWindowWidth hook in any component:

				
					import React from "react";
import useWindowWidth from "./useWindowWidth";

function WindowWidthComponent() {
  const width = useWindowWidth();

  return (
    <div>
      <h1>Window Width: {width}px</h1>
    </div>
  );
}

export default WindowWidthComponent;

				
			

In this example, the useWindowWidth custom hook tracks the width of the browser window and updates it when the window is resized. This logic can now be reused in multiple components without duplication.

Rules of Hooks

Hooks have a few important rules to follow to ensure they work correctly:

  1. Only call hooks at the top level: Don’t call hooks inside loops, conditions, or nested functions. This ensures hooks are called in the same order each time a component renders.
  2. Only call hooks from React functions: Call hooks from function components or custom hooks, not regular JavaScript functions or class components.

 

Example of Incorrect Hook Usage:

				
					// Incorrect
function Component() {
  if (someCondition) {
    const [state, setState] = useState(0); // Don’t do this
  }
}


				
			

Example of Correct Hook Usage:

				
					// Correct
function Component() {
  const [state, setState] = useState(0);
  if (someCondition) {
    // Use state here
  }
}


				
			

Conclusion

  • Hooks were introduced to simplify working with state and lifecycle methods in function components.
  • useState allows you to add local state to function components.
  • useEffect helps manage side effects, such as fetching data, updating the DOM, or subscribing to events.
  • Custom hooks enable you to encapsulate and reuse logic across components.
  • Using useEffect, you can efficiently fetch data from APIs and handle side effects in a declarative manner.

 

Hooks provide a more flexible and functional approach to working with React components, making your code cleaner and easier to maintain.