DEV Community

Softden 2005
Softden 2005

Posted on

Lifting State in React

What is Lifting State in React?

Lifting state in React refers to the practice of moving state from a child component to a parent component in order to make the state accessible to other child components. This technique is often used when two or more child components need to share and interact with the same state. By lifting the state up to the closest common ancestor, React ensures that both child components have access to the same state and can communicate with each other indirectly through their shared parent.

Why Lift State in React?

The primary reason for lifting state is to share state between components. React's data flow is unidirectional, meaning that data can only flow from parent to child, not the other way around. If two sibling components need to interact or share data, lifting the state to their common parent allows them to both receive and modify the same state.

Common scenarios for lifting state:

  1. State Sharing: When multiple child components need to access or modify the same data.
  2. Centralized State Management: Keeping the state centralized in a common ancestor simplifies the application architecture.
  3. Consistency: Ensuring that all child components have consistent data and reflect changes simultaneously.

How to Lift State in React?

To lift state, follow these steps:

  1. Identify the common ancestor component. This will be the parent component where the state will be lifted to.
  2. Move the state from the child component to the parent. The state is defined in the parent, and then passed down to the children as props.
  3. Update state via functions passed as props. The parent defines functions to modify the state, which are passed to the child components, enabling them to update the state.

Example of Lifting State in React

Consider a scenario where we have two components: TemperatureInput and BoilingVerdict. We want to lift the state of the temperature from TemperatureInput so that BoilingVerdict can determine if the temperature is above the boiling point.

import React, { useState } from 'react';

// BoilingVerdict component
function BoilingVerdict({ celsius }) {
  if (celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

// TemperatureInput component
function TemperatureInput({ temperature, onTemperatureChange }) {
  return (
    <div>
      <label>
        Temperature in Celsius:
        <input
          type="number"
          value={temperature}
          onChange={(e) => onTemperatureChange(e.target.value)}
        />
      </label>
    </div>
  );
}

// Parent component that lifts the state
function Calculator() {
  const [temperature, setTemperature] = useState('');

  const handleTemperatureChange = (temperature) => {
    setTemperature(temperature);
  };

  return (
    <div>
      <TemperatureInput temperature={temperature} onTemperatureChange={handleTemperatureChange} />
      <BoilingVerdict celsius={parseFloat(temperature)} />
    </div>
  );
}

export default Calculator;
Enter fullscreen mode Exit fullscreen mode

Explanation of the Example:

  • TemperatureInput receives the temperature and onTemperatureChange function as props from its parent (Calculator).
  • The onTemperatureChange function is called whenever the user changes the temperature input field. This updates the state in the parent component (Calculator).
  • BoilingVerdict also receives the temperature value (in Celsius) as a prop and displays whether the water would boil based on that value.

Use Case for Lifting State

In this example, consider that we are building a temperature conversion tool. You have two input fields: one for Celsius and one for Fahrenheit. Both need to interact with each other, meaning that if the user changes one temperature, the other should update automatically. Instead of maintaining separate states in each input field component, we can lift the state to a parent component to share the data between them.

Updated Example:

import React, { useState } from 'react';

// FahrenheitToCelsius component
function FahrenheitToCelsius({ fahrenheit }) {
  const celsius = ((fahrenheit - 32) * 5) / 9;
  return <p>{fahrenheit}°F is {celsius.toFixed(2)}°C</p>;
}

// CelsiusToFahrenheit component
function CelsiusToFahrenheit({ celsius }) {
  const fahrenheit = (celsius * 9) / 5 + 32;
  return <p>{celsius}°C is {fahrenheit.toFixed(2)}°F</p>;
}

// Parent component that lifts the state
function Calculator() {
  const [temperature, setTemperature] = useState({ celsius: '', fahrenheit: '' });

  const handleCelsiusChange = (celsius) => {
    const fahrenheit = (celsius * 9) / 5 + 32;
    setTemperature({ celsius, fahrenheit: fahrenheit.toFixed(2) });
  };

  const handleFahrenheitChange = (fahrenheit) => {
    const celsius = ((fahrenheit - 32) * 5) / 9;
    setTemperature({ fahrenheit, celsius: celsius.toFixed(2) });
  };

  return (
    <div>
      <div>
        <label>
          Celsius:
          <input
            type="number"
            value={temperature.celsius}
            onChange={(e) => handleCelsiusChange(e.target.value)}
          />
        </label>
        <CelsiusToFahrenheit celsius={temperature.celsius} />
      </div>
      <div>
        <label>
          Fahrenheit:
          <input
            type="number"
            value={temperature.fahrenheit}
            onChange={(e) => handleFahrenheitChange(e.target.value)}
          />
        </label>
        <FahrenheitToCelsius fahrenheit={temperature.fahrenheit} />
      </div>
    </div>
  );
}

export default Calculator;
Enter fullscreen mode Exit fullscreen mode

What’s Happening in the Example?

  1. The state (temperature) is lifted to the Calculator component, where it contains both celsius and fahrenheit.
  2. Each input field is controlled by its respective handler (handleCelsiusChange or handleFahrenheitChange), which updates the state in the parent component.
  3. Both CelsiusToFahrenheit and FahrenheitToCelsius are passed the values they need as props to update the displayed results.

Key Notes on Lifting State:

  • Unidirectional Data Flow: React's unidirectional data flow is maintained, meaning that data only flows from parent to child via props.
  • Controlled Components: In this example, both input fields are "controlled components," meaning the React state controls the input values, and the values are passed down as props.
  • State Syncing: By lifting the state, you ensure that the data is consistent across multiple components that need to share it.
  • Component Reusability: Lifting state doesn’t violate component reusability; the child components can still be reused in other contexts with different parent components.

Conclusion - Lifting State in React:

  • What: Lifting state is the practice of moving state to the closest common ancestor of components that need to share that state.
  • Why: It allows sibling components to share state while maintaining React's unidirectional data flow.
  • How: The state is lifted to the parent, and functions to update the state are passed down to the children as props.
  • When: Use lifting state when multiple components need to share and modify the same data.

Top comments (0)