Frontend Patterns

Pattern

State Lifting

Move state up the component tree to share it between sibling components.

State Management Intermediate

State Lifting

Problem

Sibling components that need to share data have no way to communicate. Developers resort to duplicating state in multiple places, leading to sync issues where one component shows outdated values while another updates. Props drilling or global state become the only options.

Solution

Move state up to the nearest common ancestor when multiple components need to share it. This creates a single source of truth that coordinates related components.

Example

This demonstrates moving state up to the nearest common ancestor when sibling components need to share data, creating a single source of truth that coordinates related components.

// Framework-agnostic state lifting
class ParentComponent extends HTMLElement {
  constructor() {
    super();
    this.value = '';  // Lifted state - shared by siblings
  }

  connectedCallback() {
    this.render();

    // Listen for changes from child components
    this.addEventListener('value-change', (e) => {
      this.value = e.detail;      // Update lifted state
      this.updateChildren();       // Sync to all children
    });
  }

  updateChildren() {
    // Update all child components with new shared value
    this.querySelectorAll('[data-value]').forEach(child => {
      child.textContent = this.value;
    });
  }

  render() {
    // Children share state through parent
    this.innerHTML = `
      <input-component></input-component>
      <display-component data-value></display-component>
    `;
  }
}

Benefits

  • Enables sibling components to share and synchronize state.
  • Creates a single source of truth, preventing sync issues.
  • Makes data flow explicit through props.
  • Simplifies coordinating related components.

Tradeoffs

  • Can lead to prop drilling if state is lifted too high.
  • May cause unnecessary re-renders in intermediate components.
  • Makes components less self-contained and reusable.
  • Requires refactoring when sharing requirements change.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.