DEV Community

Cover image for React Hooks Fundamentals: A Beginner's Guide

React Hooks Fundamentals: A Beginner's Guide

Are you new to React Hooks? React Hooks revolutionized the way dynamic web applications are built. They were introduced in React 16.8 and provide an alternative to using class components for managing state and lifecycle methods.

Before the advent of hooks, React developers had to use class-based components which made the code harder to read and comprehend. With the introduction of hooks, however, developers can now utilize functional components to manage state and other React features. This has simplified the development process and improved the readability of the code.

In this article, we'll cover the basics of React Hooks and guide you through building your initial React app. We'll also showcase the versatility of React Hooks in developing engaging and responsive web apps. Additionally, we'll provide a clear, step-by-step tutorial on integrating React Hooks into your project, highlighting their ability to streamline your code and enhance its efficiency.

What are React Hooks?

Hooks are essentially functions that allow you to use React features like state and lifecycle methods in functional components. There are several built-in hooks available in React, such as useState, useEffect, useContext, and useRef.

Allow me to briefly discuss a few of the React hooks available to us:

React useState

React useState Hook is a built-in function in React that allows you to add state to functional components. It lets you create a state variable and provide a function to update that variable, as well as the initial value for the state variable.

Here's an example of how you can use the useState Hook:

import React, { useState } from 'react';

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

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

  return (
    <div>
      <p>You clicked the button {count} times.</p>
      <button onClick={handleClick}>Click me!</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, we're using the useState Hook to create a state variable called count, which we initialize to 0. We also create a function called setCount to update the value of count.

Inside the handleClick function, we're calling setCount and passing in the new value of count, which is the current value of count plus 1.

Finally, we render the current value of count inside a paragraph tag, along with a button that, when clicked, calls the handleClick function. Every time the button is clicked, the count value is incremented by 1, and the new value is displayed on the page.

Using the useState Hook in this way allows us to add state to functional components, which makes it easier to manage the state of our application and update the UI in response to user interactions.

React useEffect

React useEffect hook is a built-in hook in React that allows you to perform side effects in a functional component. It is used to run some code after rendering the component, or after some specific state or props changes.

The useEffect hook takes two parameters: the first parameter is a function that contains the code to run after rendering the component, and the second parameter is an optional array of dependencies. The dependencies array is used to specify which state or props changes should trigger the code inside the function to run.

Here is an example of how to use the useEffect hook in a React functional component:


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

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

  useEffect(() => {
    // This code will run after the component is rendered.
    console.log('Component rendered');

    // This code will also run every time the `count` state changes.
    console.log(`Count is now ${count}`);
  }, [count]);

  const incrementCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment Count</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, we have a ExampleComponent functional component that uses the useState hook to keep track of a count state. We also use the useEffect hook to log a message to the console after rendering the component and every time the count state changes.

The second parameter of the useEffect hook is an array with the count state. This tells React to only run the code inside the function when the count state changes. If we omitted this parameter, the code would run after every render, even if the count state didn't change.

Overall, the useEffect hook is a powerful tool in React that allows you to perform side effects in functional components, and it's essential to understand how it works to build efficient and effective React applications.

React useCallback

In React, the useCallback hook is used to memoize a function, meaning that it caches the function instance so that it can be reused by child components without causing unnecessary re-renders.

The useCallback hook takes two arguments: a function to be memoized and an array of dependencies. The function will only be re-created if one of the dependencies changes. This is useful when you have a function that is expensive to create and doesn't need to be recreated every time a component re-renders.

Here's an example:

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

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

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

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

In this example, increment is a function that updates the count state when called. We wrap it with useCallback and pass [count] as the array of dependencies. This means that increment will only be recreated when count changes.

Using useCallback in this way can improve performance in larger applications by reducing unnecessary re-renders.

React useMemo

React useMemo hook is a built-in hook that is used to memoize a value, meaning it will only recompute the value when the dependencies of the function change. Memoization can improve performance by reducing the number of times a function is called.

The useMemo hook takes two arguments: a function that computes a value, and an array of dependencies. The hook will only recompute the value if one of the dependencies has changed.

Here's an example:


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

function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

function Fibonacci({ n }) {
  const [count, setCount] = useState(0);
  const fib = useMemo(() => fibonacci(n), [n]);

  return (
    <div>
      <p>The {n}th Fibonacci number is {fib}</p>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In this example, the Fibonacci component takes a prop n which specifies which Fibonacci number to calculate. The fibonacci function is a recursive function that computes the nth Fibonacci number.

We use the useMemo hook to memoize the result of the fibonacci function based on the n prop. This ensures that we only calculate the Fibonacci number when the n prop changes.

The useState hook is used to create a count state variable and a setCount function to update it. We also render a button that increments the count when clicked.

Now, every time the Fibonacci component is re-rendered, the fib value will only be recomputed if the n prop has changed. The count state variable will be updated on every re-render because it is not a dependency of the useMemo hook.

React useContext

React useContext is a built-in Hook in React that allows a functional component to consume data from a context created in a parent component.

Context in React is a way to share data between components without having to pass the props down manually through all levels of the component tree. With useContext, you can access this shared data without having to pass it down through every level of the component hierarchy.

Here's an example to demonstrate how to use useContext in React:


// Create a new context
import React, { createContext } from 'react';

export const ThemeContext = createContext();

// Wrap the App component with the ThemeContext Provider
const App = () => {
  return (
    <ThemeContext.Provider value={{ color: 'blue' }}>
      <Header />
    </ThemeContext.Provider>
  );
};

// Create a functional component that consumes data from the ThemeContext
const Header = () => {
  const theme = useContext(ThemeContext);
  return <h1 style={{ color: theme.color }}>Hello World!</h1>;
};
Enter fullscreen mode Exit fullscreen mode

In this example, we first create a new context using createContext(). Then, we wrap our Header component inside a ThemeContext.Provider component to provide the value of color: 'blue' to all components that consume this context.

In the Header component, we use useContext(ThemeContext) to access the data from the context and set the color of the h1 tag dynamically.

This is just a simple example of how to use useContext in React, but it illustrates how this Hook can be used to consume data from a context created in a parent component.

React Error Boundary

React Error Boundary is a feature in React that helps to handle errors that occur during the rendering process and prevent them from breaking the entire application. Error Boundaries are components that catch errors that occur within their child component tree and display a fallback UI instead of crashing the whole application.

Here's an example of how to use Error Boundaries in React:


import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    console.log(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>My App</h1>
        <ErrorBoundary>
          <SomeComponent />
        </ErrorBoundary>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the ErrorBoundary component is used to wrap the SomeComponent component. If an error occurs in SomeComponent, the ErrorBoundary will catch the error and display a fallback UI, which in this case is the message "Something went wrong."

The getDerivedStateFromError static method is used to update the state of the ErrorBoundary when an error occurs. The componentDidCatch method is used to log the error to an error reporting service.

By using Error Boundaries in your React application, you can prevent errors from breaking the entire application and provide a better user experience by displaying a helpful message when an error occurs.

React Keys Props

In React, key props are used in a list to help identify which items have changed, been added, or been removed. The key prop is a unique identifier for each item in the list, allowing React to efficiently update the UI when the list changes.

When a list is rendered in React, it creates a virtual DOM representation of the list elements. When the list changes, React compares the old virtual DOM with the new one to determine what has changed. If a key is not provided for each item, React may not be able to correctly identify which item has changed, leading to unexpected behavior.

Providing a key for each item in the list helps React to efficiently update the UI by only re-rendering the items that have changed. This can improve the performance of the application by reducing the amount of work required to update the UI.

In summary, the key prop is used in a list in React to help identify which items have changed, been added, or been removed. It is an essential part of optimizing the performance of a React application.

Custom React Hooks

A custom React hook is a reusable function that encapsulates stateful logic and can be shared between components in a React application. Custom hooks allow developers to abstract complex logic into reusable pieces of code, which helps to reduce repetition and improve the readability and maintainability of a React application.

Custom hooks follow a naming convention of starting with the word "use", which is a signal to React that it should be treated as a hook. By convention, custom hooks should not contain any JSX, and they should return values that can be used directly by React components, such as state variables, callbacks, or other hooks.

Here's an example of a custom hook that fetches data from an API:


import { useState, useEffect } from 'react';

function useFetchData(url) {
  const [data, setData] = useState(null);
  const [isLoading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, isLoading, error };
}

export default useFetchData;
Enter fullscreen mode Exit fullscreen mode

This hook takes a URL as its parameter and returns an object with three values: data, isLoading, and error. The data value is set to the data fetched from the URL, isLoading is a boolean value that indicates whether the data is being loaded or not, and error is set to any error that occurred during the fetch.

You can use this custom hook in your components like this:

import useFetchData from './useFetchData';

function MyComponent() {
  const { data, isLoading, error } = useFetchData('https://example.com/data');

  if (isLoading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error.message}</p>;
  }

  return <div>{JSON.stringify(data)}</div>;
}
Enter fullscreen mode Exit fullscreen mode

This hook abstracts away the implementation details of fetching data from an API, and allows you to easily reuse this logic across different components.

React Hooks have revolutionized the way developers write and manage state in React applications. They provide a simpler, more functional way to write components that is easy to read, understand, and maintain. If you are new to React or are looking to improve your React skills, learning how to use hooks is an essential step.

By mastering these fundamental concepts, you'll be well-equipped to take your React development skills to the next level and build more sophisticated and efficient applications.

Thanks for reading this article, I hope you enjoyed it as much as I did writing it. Until next time, dear readers!

❤️ Your enjoyment of this article encourages me to write further.
💬 Kindly share your valuable opinion by leaving a comment.
🔖 Bookmark this article for future reference.
🔗 If this article has truly helped you, please share it.

Top comments (2)

Collapse
 
tengfeiyue profile image
ted

nice and useful essay!

Collapse
 
alvisonhunter profile image
Alvison Hunter Arnuero | Front-End Web Developer

Thanks, Ted