Skip to main content

React Hooks: A Deep Dive

React Hooks: A Deep Dive

React Hooks are a relatively new addition to React library. They allow us to use state and other React features without having to use class components or write boilerplate code.In this article, we will take a deep dive into most commonly used React Hooks are shown in table of contents.

useState

The useState Hook allows us to add state to our functional components. It takes an initial state value as a parameter and returns an array containing the current state value and a function to update the state.

Example:


                import React, { useState } from 'react';

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

                  function increment() {
                    setCount(count + 1);
                  }

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

useEffect

The useEffect Hook allows us to perform side effects in our functional components. It takes a function as a parameter and runs it after the component has been rendered.

Example:


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

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

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

                  function increment() {
                    setCount(count + 1);
                  }

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

useContext

The useContext Hook allows us to use context in our functional components. It takes a context object as a parameter and returns the current context value.

Example:


                import React, { useContext } from 'react';

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

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

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

                  return (
                    <div>
                      <button style={{ background: theme === 'dark' ? 'black' : 'white', color: theme === 'dark' ? 'white' : 'black' }}>
                        {theme === 'dark' ? 'Dark' : 'Light'}
                      </button>
                    </div>
                  );
                }
            
        

useReducer

The useReducer Hook allows us to use a reducer function to manage state in our functional components. It takes a reducer function and an initial state value as parameters and returns an array containing the current state value and a dispatch function to update the state.

Example:


                import React, { useReducer } from 'react';

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

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

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

useCallback

The useCallback Hook allows us to memoize a function and prevent it from being recreated on every render. It takes a function and an array of dependencies as parameters and returns a memoized function.

Example:


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

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

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

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

useMemo

The useMemo Hook allows us to memoize a value and prevent it from being recalculated on every render. It takes a function and an array of dependencies as parameters and returns a memoized value.

Example:


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

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

                  const doubleCount = useMemo(() => {
                    return count * 2;
                  }, [count]);

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

useRef

The useRef Hook allows us to create a mutable variable that persists across renders. It returns an object with a current property that we can set and get the value of.

Example:


                import React, { useRef } from 'react';

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

                  const handleSubmit = (event) => {
                    event.preventDefault();
                    alert(inputRef.current.value);
                  };

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

useLayoutEffect

The useLayoutEffect Hook is similar to useEffect, but it runs synchronously after all DOM mutations are processed. This makes it useful for measuring layout and performing animations.

Example:


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

                function App() {
                  const [width, setWidth] = useState(0);

                  useLayoutEffect(() => {
                    setWidth(document.documentElement.clientWidth);
                  }, []);

                  return (
                    <div>
                      <p>Window width: {width}</p>
                    </div>
                  );
                }
            
        

useImperativeHandle

The useImperativeHandle Hook allows us to customize the instance value that is exposed to parent components when using ref. It takes a ref and a function that returns an object as parameters.

Example:


                import React, { useRef, useImperativeHandle } from 'react';

                function FancyInput(props, ref) {
                  const inputRef = useRef();

                  useImperativeHandle(ref, () => ({
                    focus: () => {
                      inputRef.current.focus();
                    }
                  }));

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

                FancyInput = React.forwardRef(FancyInput);

                function App() {
                  const inputRef = useRef();

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

                  return (
                    <div>
                    <FancyInput ref={inputRef} />
                    <button onClick={handleClick}>Focus</button>
                    </div>
                  );
                }
            
        

useMemo vs useCallback

Both useMemo and useCallback allow us to memoize values and functions, respectively, and prevent them from being recalculated or recreated on every render. The difference is that useMemo returns a memoized value, while useCallback returns a memoized function.

Use useMemo when:

  • You need to memoize a value, not a function
  • The calculation is expensive and you want to prevent it from being recalculated on every render
  • The value is not dependent on any prop or state changes

Use useCallback when:

  • You need to memoize a function, not a value
  • The function is expensive to create and you want to prevent it from being recreated on every render
  • The function is passed down to child components as a prop and you want to prevent unnecessary renders
  • The function relies on some dependencies, such as props or state, that may change frequently

useDebugValue

The useDebugValue Hook allows us to display custom debugging information for a Hook in the React DevTools. It takes a value as parameter and a formatting function that formats the value for display.

Example:


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

                function useCounter(initialValue) {
                  const [count, setCount] = useState(initialValue);
                  useDebugValue(count, count => `Count: ${count}`);
                  return [count, () => setCount(count + 1)];
                }

                function App() {
                  const [count, increment] = useCounter(0);

                  return (
                    <div>
                      <p>Count: {count}</p>
                      <button onClick={increment}>Increment</button>
                    </div>
                  );
                }
            
        

Custom Hooks

Custom Hooks are a way to reuse stateful logic across components. They are normal JavaScript functions that use one or more of the built-in Hooks and return a stateful value and/or functions to update that value.

Example:


                import { useState, useEffect } from 'react';

                function useMousePosition() {
                  const [position, setPosition] = useState({ x: 0, y: 0 });

                  function handleMouseMove(e) {
                    setPosition({ x: e.clientX, y: e.clientY });
                  }

                  useEffect(() => {
                    window.addEventListener('mousemove', handleMouseMove);
                    return () => {
                      window.removeEventListener('mousemove', handleMouseMove);
                    };
                  }, []);

                  return position;
                }

                function App() {
                  const { x, y } = useMousePosition();

                  return (
                    <div>
                      <p>The mouse position is ({x}, {y})</p>
                    </div>
                  );
                }
            
        

Conclusion

React Hooks are a powerful and flexible way to manage state and side effects in functional components. They allow us to write more concise and reusable code, and to share stateful logic between components. By using the built-in Hooks and creating custom Hooks, we can create complex and dynamic user interfaces with ease.

React Hooks are a powerful and flexible way to manage state and side effects in functional components. They allow us to write more concise and reusable code, and to share stateful logic between components. By using the built-in Hooks and creating custom Hooks, we can create complex and dynamic user interfaces with ease.

While Hooks are a great addition to React, they are not always necessary or appropriate. Class components still have their place, especially in legacy code or in cases where we need to leverage their full lifecycle methods or access to the DOM. Additionally, Hooks are not a replacement for good programming practices, such as code organization, separation of concerns, and testing.

It is important to use Hooks responsibly and to understand their limitations and tradeoffs. By doing so, we can take advantage of their benefits and create better React applications.

© 2023 React Hooks Deep Dive

Comments

Popular posts from this blog

Everything You Need to Know About CSS Grid

Everything You Need to Know About CSS Grid We have a thorough manual on CSS grid, which covers all aspects of settings for both parent container and child elements of grid. Back to TOC Table of Contents Introduction Basics Important Terminology Grid Properties Special Units & Functions Fluid Columns Snippet Animation Introduction CSS Grid Layout, also known as "Grid" or "CSS Grid", is a revolutionary two-dimensional grid-based layout system that completely transforms the way we design user interfaces. In the past, CSS was used to layout web pages, but it was never very effective. We used tables, floats, positioning, and inline-...

Styling SVGs with CSS

Styling SVGs with CSS SVGs are a versatile and powerful format for creating high-quality graphics on the web. However, by default, SVGs can appear plain and unstyled, which can make them feel out of place in a modern web design.That's where CSS comes in. By using CSS to style SVGs, you can add color, gradients, shadows, animations, and other visual effects that make them more dynamic and engaging. Back to TOC Table of Contents What is SVG? Inline vs External SVGs Basic Styling Techniques Advanced Styling Techniques Animation Demo • What is SVG? SVG stands for Scalable Vector Graphics. It is a vector graphics format that uses XML to define two-dimensional graphics. Unlike raster graphics, such as JPEGs or PNGs, SVGs can be scaled without losing quality, making them ideal for use on websites and other digital media. • Inline vs External SVGs SVGs can be...

CSS property border-image-outset

Page Title The border-image-outset property in CSS defines the extent to which an element's border-image extends beyond its border-box, creating a space between the element's border-image area and the edge of its border. .container { border-style: ridge; border-width: 3rem; border-image-source: url('path/to/image.jpg'); border-image-slice: 70; border-image-width: 40%; border-image-repeat: repeat; border-image-outset: 2; } See the Pen Untitled by Mushtaq Ahmad ( @MushtaqPhysicist ) on CodePen . The CSS border-image-outset property, also known as the "Edge Overhang" property, is specified in the CSS Backgrounds and Borders Module Level 3. Its purpose is to enable the border image area to extend beyond an element's border-box, which is accurately described by the term "Edge Overhang". S...