VDone Demo VDone Demo
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)

Nikolay Tuzov

Backend Developer
Home
  • Articles

    • JavaScript
  • Study Notes

    • JavaScript Tutorial
    • Professional JavaScript
    • ES6 Tutorial
    • Vue
    • React
    • TypeScript: Build Axios from Scratch
    • Git
    • TypeScript
    • JS Design Patterns
  • HTML
  • CSS
  • Technical Docs
  • GitHub Tips
  • Node.js
  • Blog Setup
  • Learning
  • Interviews
  • Miscellaneous
  • Practical Tips
  • Friends
About
Bookmarks
  • Categories
  • Tags
  • Archives
GitHub (opens new window)
  • 核心概念

    • Introduction to JSX
    • Rendering Elements
    • Components & Props
    • State & Lifecycle
    • Handling Events
    • Conditional Rendering
    • Lists & Keys
    • Forms
    • Lifting State Up (Shared State)
      • Composition vs Inheritance
      • Thinking in React
    • 高级指引

    • Hook

    • 案例演示

    • 《React》笔记
    • 核心概念
    xugaoyi
    2021-03-26
    Contents

    Lifting State Up (Shared State)

    # 09. Lifting State Up (Shared State)

    Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor.

    In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called "lifting state up".

    An example of two input fields sharing data:

    const scaleNames = {
      c: 'Celsius',
      f: 'Fahrenheit'
    };
    
    // Convert to Celsius
    function toCelsius(fahrenheit) {
      return (fahrenheit - 32) * 5 / 9;
    }
    
    // Convert to Fahrenheit
    function toFahrenheit(celsius) {
      return (celsius * 9 / 5) + 32;
    }
    
    // Convert: returns empty for empty input, otherwise returns a float rounded to 3 decimal places
    function tryConvert(temperature, convert) {
      const input = parseFloat(temperature);
      if (Number.isNaN(input)) {
        return '';
      }
      const output = convert(input);
      // Math.round returns the nearest integer
      const rounded = Math.round(output * 1000) / 1000;
      return rounded.toString();
    }
    
    // Whether water would boil
    function BoilingVerdict(props) {
      if (props.celsius >= 100) {
        return <p>The water would boil.</p>;
      }
      return <p>The water would not boil.</p>;
    }
    
    // Child component - input field
    class TemperatureInput extends React.Component {
      constructor(props) {
        super(props); // Receive props from parent
        this.handleChange = this.handleChange.bind(this); // Bind callback and fix this
      }
    
      // Handle change
      handleChange(e) {
        // e is a synthetic event object, access value via e.target.value
        // Call the onTemperatureChange function passed from the parent, and pass the value
        this.props.onTemperatureChange(e.target.value);
    
        // When the child input value changes, call the parent's onTemperatureChange method and emit the value.
        // Also, the naming convention for onTemperatureChange: `on<ChildComponent>Change`
      }
    
      render() {
        // Receive temperature value from parent
        const temperature = this.props.temperature;
        // Receive scale from parent
        const scale = this.props.scale;
    
        return (
          <fieldset>
            <legend>Enter temperature in {scaleNames[scale]}:</legend>
            <input value={temperature}
                   onChange={this.handleChange} />
          </fieldset>
        );
      }
    }
    
    
    // Parent component - calculator
    class Calculator extends React.Component {
      constructor(props) {
        super(props); // Receive props from parent
    
        // Bind event callbacks and fix this
        this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
        this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
        // Create initial state values
        this.state = {temperature: '', scale: 'c'};
      }
    
      // Handle Celsius change
      handleCelsiusChange(temperature) {
        // temperature receives the argument from the child, and modifies state via setState
        this.setState({scale: 'c', temperature});
      }
    
      // Handle Fahrenheit change
      handleFahrenheitChange(temperature) {
        // temperature receives the argument from the child, and modifies state via setState
        this.setState({scale: 'f', temperature});
      }
    
      // Render function (called whenever state changes)
      render() {
        // Get current state values
        const scale = this.state.scale;
        const temperature = this.state.temperature;
    
        // Get the corresponding temperature data based on scale
        const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
        const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
    
        // Return the rendered elements
        // Insert TemperatureInput child components with appropriate parameters, onTemperatureChange set to callback functions
        return (
          <div>
            <TemperatureInput
              scale="c"
              temperature={celsius}
              onTemperatureChange={this.handleCelsiusChange} />
            <TemperatureInput
              scale="f"
              temperature={fahrenheit}
              onTemperatureChange={this.handleFahrenheitChange} />
            <BoilingVerdict
              celsius={parseFloat(celsius)} />
          </div>
        );
      }
    }
    
    // Render to DOM
    ReactDOM.render(
      <Calculator />,
      document.getElementById('root')
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127

    Try it on CodePen (opens new window)

    Note

    1. The parent passes state values to all child components
    2. When a child modifies a value, it calls the parent's method and passes the value out
    3. The parent receives the value and modifies state
    4. After state is modified, the render function re-executes, returning to step 1

    # Summary

    • Any mutable data should have a single corresponding "source of truth"

      • Usually, state is first added to the component that needs it for rendering
      • Then, if other components also need it, you can lift it up to their closest common ancestor
      • You should rely on the top-down data flow (opens new window), rather than trying to sync state between different components
    • Any state that "lives" in a component can only be modified by that component itself

    • If some data can be derived from either props or state, it probably shouldn't be in the state. (Like the values obtained via the tryConvert method in the example above.)

    # React Developer Tools (Debug)

    When you see something wrong in the UI, you can use React Developer Tools (opens new window) to inspect the props of the problem component and search up the component tree until you find the component responsible for updating the state.

    Edit (opens new window)
    #React
    Last Updated: 2026/03/21, 12:14:36
    Forms
    Composition vs Inheritance

    ← Forms Composition vs Inheritance→

    Recent Updates
    01
    How I Discovered Disposable Email — A True Story
    06-12
    02
    Animations in Grid Layout
    09-15
    03
    Renaming a Git Branch
    08-11
    More Articles >
    Theme by VDone | Copyright © 2026-2026 Nikolay Tuzov | MIT License | Telegram
    • Auto
    • Light Mode
    • Dark Mode
    • Reading Mode