Day 5: React Learning Journey: Understanding State in React

Sonal DiwanSonal Diwan
6 min read

Introduction

Welcome to Day 5 of your React Learning Journey! Yesterday, we explored props and how they allow data to flow from parent to child components. Today, we’re moving on to one of the most fundamental concepts in React—State. While props are essential for passing data down the component tree, state is what gives components the ability to dynamically change and update their content in response to user actions or other triggers.

Let’s dive in and understand what state is, how it works, and why it’s crucial for building interactive applications in React.

What is State in React?

In React, state refers to an object that holds data specific to a component. Unlike props, which are passed to a component, state is managed and updated within the component itself. It’s what gives components the ability to be dynamic and interactive.

State controls things like user inputs, button clicks, toggles, and other interactions. Whenever state changes, React automatically re-renders the component to reflect the new state. This is what makes React apps responsive and dynamic.

Think of state as the internal data storage for your component, a bit like a person’s memory—it stores information that the component might need to remember or change as the app runs.

How State Differs from Props

It’s important to distinguish between state and props. Both hold information that a component uses, but they serve different purposes:

  • Props are read-only and passed down from parent components. They cannot be changed by the component receiving them.

  • State is mutable and managed internally within the component. The component can update its own state over time.

In simple terms: props are like parameters passed into a function, while state is like local variables inside that function.

Why State is Important in React

State is essential because it enables React components to track and respond to changes. Imagine you have a counter component. Without state, the component would always display the same number. With state, you can let users increase or decrease the number dynamically. State also allows components to render content conditionally, respond to user inputs, and much more.

Every time state is updated, React re-renders the component, ensuring the UI always reflects the most current data.

Setting State in Class Components

In older versions of React, components were primarily built using class components, and state was managed through this.state. Here’s an example of setting state in a class component:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return <h1>{this.state.count}</h1>;
  }
}

In the example above, this.state holds the count property, and you can access this state within the render method.

Setting State in Functional Components with useState

In modern React development, functional components and React Hooks are the standard. The useState hook allows us to add state to functional components without needing classes. Here’s how it works:

import { useState } from 'react';

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

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

With useState, you initialize the state (in this case, count) and provide a function (setCount) to update it. Every time the state is updated with setCount, the component re-renders to reflect the new value.

Updating State: The Right Way

A critical rule in React is to never mutate the state directly. You must always use the setter function (e.g., setState or setCount) to update the state. For example:

this.setState({ count: this.state.count + 1 });

In the case of functional components, you’d use:

setCount(count + 1);

Directly modifying state like this:

this.state.count = 10; // BAD

would lead to unpredictable behavior because React won’t be aware that the state has changed. Always rely on the proper React mechanisms to update state.

Handling Complex State

Sometimes, you may need to store more complex data in state, like objects or arrays. Here’s an example of managing an object in state:

const [user, setUser] = useState({ name: 'John', age: 25 });

function updateUserName() {
  setUser({ ...user, name: 'Jane' });
}

Notice how we used the spread operator (...user) to create a new copy of the state object and update only the name field. This maintains immutability, which is crucial for React to detect changes and re-render appropriately.

Functional Updates in useState

Sometimes state updates depend on the previous state. In such cases, you should use the functional form of the setState function, which provides access to the previous state:

setCount(prevCount => prevCount + 1);

This ensures that the state update is based on the most recent state, avoiding issues with stale state values.

State and Re-Rendering: How it Works

Whenever state changes, React automatically re-renders the component. This is one of the key features of React’s declarative nature. Instead of manually updating the UI based on state changes (like in vanilla JavaScript), React automatically keeps your UI in sync with the state.

However, excessive or unnecessary state updates can lead to performance issues, especially in larger applications. It’s important to be mindful of how often state changes occur and optimize components to avoid unnecessary re-renders.

Initializing State with Props

In some cases, you might want to initialize a component’s state based on the props it receives:

function UserProfile({ user }) {
  const [name, setName] = useState(user.name);

  return <h1>{name}</h1>;
}

However, avoid updating the state based on props after the initial render. If the props change, state won’t automatically update unless you use useEffect or another mechanism to sync them.

Handling Asynchronous State Updates

State updates in React are asynchronous. This means that multiple state updates may not happen immediately. React batches state updates for performance reasons. If you need to perform an action after a state update, use a useEffect hook or rely on functional updates.

Using Multiple State Variables with useState

You’re not limited to a single state variable per component. In functional components, you can manage multiple state variables:

const [name, setName] = useState('');
const [age, setAge] = useState(0);

This allows you to break down state management

into smaller, more manageable pieces.

Common Pitfalls in State Management

  • Overusing state: Not every piece of data needs to be in the state. Only track what truly needs to trigger a UI update.

  • Modifying state directly: Always use the state setter functions like setState or setCount to update the state.

  • Not batching updates: React batches multiple state updates for performance. Be cautious when expecting immediate updates.

Conclusion

State is the engine that powers the interactivity in your React components. By understanding how state works, how to manage it, and how it differs from props, you’ve unlocked the ability to create truly dynamic applications. In the next part of our journey, we’ll explore more advanced state management techniques, including global state handling with context and external libraries.

Keep experimenting with state, and remember that it's the key to building responsive, user-driven interfaces in React.

FAQs

  1. Can I use both state and props in the same component?
    Yes, components can use both state and props simultaneously. Props handle external data, while state manages internal data.

  2. How do I handle deeply nested state updates?
    For deeply nested state, consider using a state management library like Redux, or manage state immutably with helpers like the spread operator or immer.js.

  3. What happens if I directly mutate state?
    Directly mutating state will cause bugs and unpredictable behavior since React won’t know the state has changed.

  4. Why does updating state in React cause re-rendering?
    React re-renders components to ensure the UI always matches the current state. State changes trigger this re-rendering process.

  5. How can I manage global state in a React app?
    To manage global state, you can use the Context API or state management libraries like Redux or Zustand.

1
Subscribe to my newsletter

Read articles from Sonal Diwan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sonal Diwan
Sonal Diwan

Data-Driven Fresher | Leveraging full stack technologies | Exploring tech-trends