Developer Guides

Understanding React Hooks: useState and useEffect Explained

Learn how to utilize React hooks, specifically useState and useEffect, for state management and side effects in functional components.

5 min read

React hooks are a powerful feature introduced in React 16.8 that enable developers to manage state and lifecycle logic in functional components. Among the many hooks provided by React, two of the most commonly used are useState and useEffect. This guide covers how to effectively use these hooks for state management and handling side effects.

Prerequisites for Working with React Hooks

Before diving into React hooks, ensure you have the following in place:

prerequisites

  • Basic knowledge of React and JavaScript
  • Node.js installed (required for initializing a React project)
  • A code editor such as Visual Studio Code
  • An initialized React project using create-react-app
  • Familiarity with functional components

Steps to Implement useState for State Management

The useState hook provides a way to add state to functional components in React. Follow these steps to correctly implement useState in your component:

steps

  1. Import useState: Ensure useState is imported from React:

    jsx
    import React, { useState } from 'react';
  2. Declare State Variable: Use the useState hook to declare a state variable with its default value:

    jsx
    const [count, setCount] = useState(0);
  3. Access the State Variable: Use the state variable in your component's JSX:

    jsx
    return <p>Current count: {count}</p>;
  4. Update the State Variable: Use the setter function (returned by useState) to update the state:

    jsx
    return <button onClick={() => setCount(count + 1)}>Increase</button>;

Using useEffect to Handle Component Side Effects

The useEffect hook allows you to perform side effects within functional components, such as fetching data, subscribing to events, or manually modifying the DOM.

steps

  1. Import useEffect: Similar to useState, import useEffect from React:

    jsx
    import React, { useEffect } from 'react';
  2. Define Effect Logic: Place the logic to be executed inside the useEffect callback function. This runs after the component is rendered:

    jsx
    useEffect(() => {
        console.log('This runs after every render');
    });
  3. Add a Dependency Array (Optional): If you want your effect to run only when specific values change, provide an array of dependencies:

    jsx
    useEffect(() => {
        console.log('This runs when the "count" changes');
    }, [count]);
  4. Run Effect Once: To execute an effect only once (e.g., on component mount), provide an empty array [] as the second argument:

    jsx
    useEffect(() => {
        console.log('This runs only once');
    }, []);
  5. Cleanup: Return a cleanup function to avoid memory leaks (e.g., removing subscriptions):

    jsx
    useEffect(() => {
        const timer = setTimeout(() => setCount(count + 1), 1000);
        return () => clearTimeout(timer);
    }, [count]);

Code Implementation Example

Below is a complete example combining useState and useEffect to manage state and side effects:

React App with useState and useEffect

# Step 1: Create a new React app
npx create-react-app react-hooks-demo
cd react-hooks-demo

# Step 2: Open the App component in your editor
code src/App.js

# Step 3: Replace the contents of App.js

// App.js
import React, { useState, useEffect } from 'react';

function App() {
    const [favoriteColor, setFavoriteColor] = useState('red');

    useEffect(() => {
        console.log(`Your favorite color is ${favoriteColor}`);
    }, [favoriteColor]);

    const changeColor = () => {
        setFavoriteColor('blue');
    };

    return (
        <div>
            <h1>My favorite color is {favoriteColor}</h1>
            <button onClick={changeColor}>Change to Blue</button>
        </div>
    );
}

export default App;

# Step 4: Start the development server
npm start

Common Pitfalls and Best Practices


Use Case: Handling State and Effects Together

Choose useState and useEffect Together When...

  • Fetching Data on Component Mount: Use useEffect with an empty dependency array to load data on initial render.
  • Interdependent Updates: Use useState for managing dependent values and trigger side effects with useEffect.
  • Timers or Animation: Combine useState to drive changes and use useEffect for interval or timeout management.

Summary of React Hooks Essentials


FAQ

What are the differences between useState and useEffect?

useState manages local state, providing a setter function to update its value. useEffect, on the other hand, handles side effects like data fetching or integrating DOM manipulations after rendering.

Why does useEffect create infinite loops sometimes?

Infinite loops occur when the dependency array of useEffect is missing or incorrectly set. The effect will run after every render if dependencies are not specified.

Can I perform data fetching inside useEffect?

Yes, useEffect is commonly used for data fetching. By including the variables that trigger the fetch within its dependency array, you can re-fetch data only when those specific variables change.


Official reference: React documentation.