How to Update Lifted State in React

Sharing state between components in React often requires “lifting state up” to their closest common ancestor. This article explains how to lift state up, how to update that lifted state from child components using callback functions, and when to consider alternative state management solutions.

The Concept of Lifting State Up

In React, data flows downward (unidirectional data flow). When two or more sibling components need access to the same changing state, you must move that state up to their nearest common parent component. The parent then passes the state down to the children as read-only properties (props).

To allow child components to update this state, the parent must also pass down a state-updating function (a callback) as a prop.

Step-by-Step: How to Update Lifted State

Updating lifted state involves three main steps: defining the state in the parent, passing the state and updater function to the children, and triggering the updater function from the child.

1. Define State and Handler in the Parent Component

First, declare the state in the common parent component using the useState hook. Next, create a handler function that will update this state when called.

import { useState } from 'react';

function ParentComponent() {
  const [sharedText, setSharedText] = useState('');

  const handleTextChange = (newValue) => {
    setSharedText(newValue);
  };

  return (
    <div>
      <InputComponent value={sharedText} onValueChange={handleTextChange} />
      <DisplayComponent value={sharedText} />
    </div>
  );
}

2. Pass State and Handlers as Props

In the example above, the parent component passes: * The current state (sharedText) to DisplayComponent to be rendered. * The current state (sharedText) and the updater function (handleTextChange) to InputComponent.

3. Trigger the Update from the Child Component

The child component receiving the updater function can trigger it in response to user interactions, such as an onChange or onClick event.

function InputComponent({ value, onValueChange }) {
  return (
    <input
      type="text"
      value={value}
      onChange={(e) => onValueChange(e.target.value)}
      placeholder="Type something..."
    />
  );
}

function DisplayComponent({ value }) {
  return <p>The current value is: {value}</p>;
}

When the user types into the input field, the onChange event fires, executing onValueChange. This runs the handleTextChange function in the parent component, updating the state. The parent re-renders, passing the newly updated value down to both child components.

Best Practices and Alternatives

While lifting state up is a fundamental React pattern, keeping your application maintainable requires following a few best practices: