HomeTutorsContact

React hooks explained with examples

By Gulshan Saini
Published in ReactJS
January 01, 2023
8 min read

What are hooks in react

In React, a hook is a function that allows you to “hook into” React features. Hooks let you use state and other React features without writing a class.

There are several built-in hooks in React, such as useState and useEffect. You can also create your own custom hooks to reuse stateful logic between different components.

Using hooks can make your code easier to read, understand, and test, and can allow you to share stateful logic between components.

Different types of react hooks

There are several built-in hooks in React:

  • useState: This hook allows you to add state to functional components. It returns an array with two elements: the current state value and a function that lets you update the state.

  • useEffect: This hook allows you to perform side effects in functional components. It is called after the component renders, and it takes a function that contains the side effects you want to perform.

  • useContext: This hook allows you to consume context in a functional component. It takes the context object and returns the current context value.

  • useReducer: This hook is similar to useState, but it allows you to manage complex state logic in a single function. It takes a reducer function and returns the current state value and a dispatch function that you can use to update the state.

  • useCallback: This hook returns a memoized version of a callback function. It can be useful for optimizing performance by preventing unnecessary re-renders of components that use the callback.

  • useMemo: This hook returns a memoized value. It can be useful for optimizing performance by preventing unnecessary recalculation of values.

  • useRef: This hook returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

  • useImperativeHandle: This hook allows you to pass a ref to a child component and access the value of the ref from the parent component.

There are also many other hooks available in various React libraries and packages. You can also create your own custom hooks to reuse stateful logic between different components.

useState hook with example

useState is a hook that allows you to add state to functional components. It takes a single argument, which is the initial state, and returns an array with two elements: the current state value and a function that lets you update the state.

Here’s an example of how you might use the useState hook in a functional component:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  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 add a piece of state called count to the component. The initial value of count is 0. The hook returns an array with the current value of count (which is 0) and a function called setCount that allows you to update the value of count.

The component renders a button and a paragraph element. The paragraph element displays the current value of count, and the button has an onClick event handler that increases the value of count by 1 when it is clicked.

Every time the button is clicked, the setCount function is called with the new value of count, which causes the component to re-render with the updated value of count.

useEffect with example

useEffect is a hook that allows you to perform side effects in functional components. It is called after the component renders, and it takes a function that contains the side effects you want to perform.

Here’s an example of how you might use the useEffect hook in a functional component:

import { useState, useEffect } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

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

In this example, the useEffect hook is used to update the document title when the value of count changes. The hook function takes no arguments, and it is called after the component renders.

Every time the button is clicked, the setCount function is called with the new value of count, which causes the component to re-render with the updated value of count. The useEffect hook function is called after the render, and it updates the document title with the new value of count.

useEffect is useful for performing side effects like making network requests, setting up subscriptions, and manually changing the DOM in response to state changes. It is similar to the componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle methods in class-based components.

What are side effects?

In the context of React, a side effect is an action or a change that occurs as a result of a component’s render. Side effects can include things like making network requests, setting up subscriptions, and manually changing the DOM in response to state changes.

For example, consider a component that fetches data from a server when it renders. The act of fetching the data is a side effect of the component’s render, because it is an action that occurs as a result of the render, but is not directly related to the rendering itself.

Another example of a side effect might be setting up a subscription to a data source. If a component subscribes to a data source when it renders, and then unsubscribes when it unmounts, the act of subscribing and unsubscribing are side effects of the component’s render.

Side effects can be useful for separating concerns and making components easier to reason about, because they allow you to perform actions that are not directly related to the rendering of the component. However, it is important to manage side effects carefully, because they can have unintended consequences if they are not handled properly.

useContext with example

useContext is a hook that allows you to consume context in a functional component. It takes the context object and returns the current context value.

Here’s an example of how you might use the useContext hook in a functional component:

import { useContext } from 'react';

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const theme = useContext(ThemeContext);

  return (
    <div style={{ background: theme.background, color: theme.foreground }}>
      Themed Toolbar
    </div>
  );
}

In this example, the useContext hook is used to consume the ThemeContext in the Toolbar component. The ThemeContext has a dark theme set as its value, and the Toolbar component uses the useContext hook to retrieve the current theme from the context. The theme is then used to style the div element that the Toolbar component renders.

useContext is useful for avoiding prop drilling, which is when you have to pass props down through multiple levels of components just to get to the component that needs the prop. It allows you to access context values directly from the functional component, without having to pass the context value down through props.

useReducer with example

useReducer is a hook that is similar to useState, but it allows you to manage complex state logic in a single function. It takes a reducer function and returns the current state value and a dispatch function that you can use to update the state.

Here’s an example of how you might use the useReducer hook in a functional component:

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:
      throw new Error();
  }
}

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

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </>
  );
}

In this example, the useReducer hook is used to manage the state of a counter component. The hook takes a reducer function called reducer and an initial state object with a count of 0. The hook returns an array with the current state value and a dispatch function.

The component renders two buttons and a paragraph element that displays the current count. The buttons have onClick event handlers that dispatch actions to the reducer function to increment or decrement the count. The reducer function updates the state based on the action type, and the component re-renders with the updated state.

useReducer can be useful for managing complex state logic that involves multiple state values or requires logic that goes beyond a simple update. It is similar to the reducer function in a Redux store.

useCallback with example

useCallback is a hook that returns a memoized version of a callback function. It can be useful for optimizing performance by preventing unnecessary re-renders of components that use the callback.

Here’s a simple example of how you might use the useCallback hook:

import { useCallback } from 'react';

function MyComponent(props) {
  const { onClick } = props;

  // The function passed to useCallback will only be re-created if
  // one of the dependencies changes.
  const memoizedOnClick = useCallback(() => {
    console.log('Clicked');
  }, [onClick]);

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

In this example, the useCallback hook is used to create a memoized version of the onClick callback function that is passed to the component as a prop. The hook function takes the callback function and an array of dependencies as arguments. If the dependencies have not changed, the hook will return the same function instance on every render.

This can be useful for preventing unnecessary re-renders of components that use the callback, because the component will only re-render if the dependencies have changed.

useCallback is similar to the React.useMemo hook, but it is specifically for creating memoized callbacks. It is often used in conjunction with the React.memo higher-order component to optimize the performance of components that depend on expensive calculations or slow-running functions.

useMemo hook with example

useMemo is a hook that returns a memoized value. It can be useful for optimizing performance by preventing unnecessary recalculation of values.

Here’s a simple example of how you might use the useMemo hook:

import { useMemo } from 'react';

function MyComponent(props) {
  const { data } = props;

  // The function passed to useMemo will only be re-calculated if
  // one of the dependencies changes.
  const memoizedValue = useMemo(() => {
    // Expensive calculation
    return data.reduce((a, b) => a + b, 0);
  }, [data]);

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

In this example, the useMemo hook is used to memoize the result of an expensive calculation that is based on the data prop. The hook function takes a function that performs the calculation and an array of dependencies as arguments. If the dependencies have not changed, the hook will return the same value on every render.

This can be useful for preventing unnecessary recalculation of values, because the calculation will only be performed if the dependencies have changed.

useMemo is similar to the React.useCallback hook, but it is specifically for creating memoized values. It is often used in conjunction with the React.memo higher-order component to optimize the performance of components that depend on expensive calculations or slow-running functions.

What is difference between React.memo and useMemo?

React.memo is a higher-order component (HOC) that allows you to optimize the performance of functional components by memoizing the component’s rendered output. It works by creating a new component that wraps the original component and only re-renders the wrapped component if its props have changed.

useMemo is a hook that returns a memoized value. It can be useful for optimizing performance by preventing unnecessary recalculation of values.

The main difference between React.memo and useMemo is that React.memo is used to optimize the performance of a component by memoizing its rendered output, while useMemo is used to memoize a value that is calculated inside a component.

React.memo is often used in conjunction with the useMemo hook to optimize the performance of functional components that depend on expensive calculations or slow-running functions. In this case, useMemo would be used to memoize the result of the expensive calculation, and React.memo would be used to prevent the component from re-rendering if the calculation’s dependencies have not changed.

Here’s an example of how you might use React.memo and useMemo together to optimize the performance of a functional component:

import { useMemo } from 'react';

function ExpensiveComponent(props) {
  // Memoize the result of the expensive calculation
  const memoizedValue = useMemo(() => {
    // Expensive calculation
    return props.data.reduce((a, b) => a + b, 0);
  }, [props.data]);

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

// Only re-render the ExpensiveComponent if its props have changed
export default React.memo(ExpensiveComponent);

In this example, the useMemo hook is used to memoize the result of an expensive calculation that is based on the props.data prop. The React.memo HOC is used to wrap the ExpensiveComponent and prevent it from re-rendering if its props have not changed. This can help to optimize the performance of the component by preventing unnecessary recalculation of the expensive calculation.

useRef hook with example

useRef is a hook that returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

Here’s an example of how you might use the useRef hook:

import { useRef } from 'react';

function TextInput() {
  const inputEl = useRef(null);

  const handleClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={handleClick}>Focus the input</button>
    </>
  );
}

In this example, the useRef hook is used to create a ref that points to the input element. The ref is passed to the input element using the ref attribute, and the ref is used to focus the input when the button is clicked.

useRef can be useful for accessing DOM elements, for instance to focus an input element or measure the dimensions of an element. It can also be useful for storing mutable values that need to persist between renders, such as timers or intervals.

You should use useRef instead of useState when you need to store a value that will not trigger a re-render when it changes. For example, if you store a timer ID in a useState variable, the component will re-render every time the ID changes, which can lead to unnecessary re-renders and poor performance. Using a useRef variable to store the timer ID will avoid this issue, because the component

useImperativeHandle hook with example

useImperativeHandle is a hook in React that allows you to pass a ref to a child component and access the value of the ref from the parent component. It’s often used when you want the parent component to have access to the methods of the child component, but you don’t want to pass the methods as props because you don’t want the parent to be able to call the methods itself.

Here’s an example of how useImperativeHandle can be used:

import { useRef, useImperativeHandle } from 'react';

function Child(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} />;
}

const ForwardedChild = forwardRef(Child);

function Parent() {
  const childRef = useRef(null);

  const handleClick = () => {
    childRef.current.focus();
  };

  return (
    <div>
      <ForwardedChild ref={childRef} />
      <button onClick={handleClick}>Focus Child Input</button>
    </div>
  );
}

In this example, the Parent component has a ref called childRef that is passed to the Child component via the ref prop. The Child component uses useImperativeHandle to define a focus method that focuses the input element. The Parent component can then call the focus method on the Child component by accessing it through the childRef ref.


Tags

#react
Previous Article
What are HOC (higher order components)?

Related Posts

ReactJS
What are HOC (higher order components)?
January 01, 2023
1 min
Gulshan Saini

Gulshan Saini

Fullstack Developer

Topics

JavaScript
Angular
ReactJS
Typescript
Linux

Subscribe to our newsletter!

We'll send you the best of our blog just once a month. We promise.

Quick Links

Contact UsBrowserCSSPythonPuppeteer

Social Media