Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does React implement its two-way data binding?

I've seen examples showing how to implement two-way binding in React but none explain how this feature actually functions internally.

In this codepen example taken from React's website, if you comment out line 11:

handleChange(event) {
  // this.setState({value: event.target.value});
}

You'll notice how React is enforcing the 2-way binding by making sure the view doesn't update in a way that is inconsistent with the data model even after the user directly modifies the input box. But how is it doing that?

Given how event.target.value has the input the user just entered in the scope of handleChange but becomes empty in the view nonetheless, it implies that at some point the value was reset by React. Also, it's not resetting the value simply to empty but according to the latest data model, this can be tested by making the following changes to the code:

constructor(props) {
  super(props);
  this.state = {value: ''};

  this.handleChange = this.handleChange.bind(this);
  this.handleSubmit = this.handleSubmit.bind(this);

  this.counter = 0;
}

handleChange(event) {
  if (this.counter < 3) {
    this.setState({value: event.target.value});
    this.counter++;
  }
}

This time, the input box changes the first three times and then afterwards it resets according to what the last model state was.

My guess is the following:

  1. HTML Element is modified according to user input.
  2. "onchange" event handler is triggered.
  3. State is NOT updated.
  4. Because the state was not updated, React diffs a cached Virtual-DOM representation of the component against the Real-DOM Element that was just changed by the user.
  5. React updates the attributes of the Real-DOM Element to be consistent with its Virtual-DOM representation.

Had the state been changed, then the cached Virtual-DOM representation would've been "dirtied" and this would've triggered a re-rendering of the virtual element. However, the rest of the flow I described above would still apply meaning that no new HTML node would've been created and only the attributes of the existing one would've been updated (assuming the element type, e.g. <input>, didn't change).

That is my best guess as to what the internal mechanism of this feature might be. Please let me know if I'm wrong and if so, what is the real answer to the question.

Thanks!

like image 316
kazuoua Avatar asked Oct 16 '25 11:10

kazuoua


1 Answers

This is a neat question and I'll give it my best shot if anyone sees any mistakes in my answer please point them out and I'll gladly apply edit corrections. Digging through the React source here's what I've come up with:

  1. HTML is modified and an event is called in the DOM

  2. React queues the event / synthetic event dispatch inside EventPropagators.js

  3. Events are dequeued in order (this event has no effect on the state)

  4. At the end of the event loop, react uses a restoreTarget to restore controlled components to represent the state in ReactControlledComponent.js :

Use to restore controlled state after a change event has fired.

We perform this translation at the end of the event loop so that we always receive the correct fiber here

This is where the magic happens. The restoreTarget is a component's state, so react triggers a regular render() at this point to redraw the restoreTarget which I imagine would go through its standard virtual-DOM vs real-DOM reconciliation algorithm.

As per your example, handleChange() is executed (with or without a state change) after which restoreTarget is redrawn and renders a component that accurately represents the state at that moment where count = 3.

like image 129
Alexei Darmin Avatar answered Oct 19 '25 02:10

Alexei Darmin