Two-Way Binding Helpers Edit on GitHub

ReactLink is an easy way to express two-way binding with React.

Note:

If you're new to the framework, note that ReactLink is not needed for most applications and should be used cautiously.

In React, data flows one way: from owner to child. This is because data only flows one direction in the Von Neumann model of computing. You can think of it as "one-way data binding."

However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React state when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.

In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call setState() on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See our forms documentation for more information.

Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React state -- is concise and supports a wide variety of applications. We've provided ReactLink: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React state.

Note:

ReactLink is just a thin wrapper and convention around the onChange/setState() pattern. It doesn't fundamentally change how data flows in your React application.

ReactLink: Before and After #

Here's a simple form example without using ReactLink:

var NoLink = React.createClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  handleChange: function(event) {
    this.setState({message: event.target.value});
  },
  render: function() {
    var message = this.state.message;
    return <input type="text" value={message} onChange={this.handleChange} />;
  }
});

This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use ReactLink to save us some typing:

var LinkedStateMixin = require('react-addons-linked-state-mixin');

var WithLink = React.createClass({
  mixins: [LinkedStateMixin],
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  render: function() {
    return <input type="text" valueLink={this.linkState('message')} />;
  }
});

LinkedStateMixin adds a method to your React component called linkState(). linkState() returns a ReactLink object which contains the current value of the React state and a callback to change it.

ReactLink objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.

Note that checkboxes have a special behavior regarding their value attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to on). The value attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use checkedLink instead of valueLink: <input type="checkbox" checkedLink={this.linkState('booleanValue')} />

Under the Hood #

There are two sides to ReactLink: the place where you create the ReactLink instance and the place where you use it. To prove how simple ReactLink is, let's rewrite each side separately to be more explicit.

ReactLink Without LinkedStateMixin #

var WithoutMixin = React.createClass({
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  handleChange: function(newValue) {
    this.setState({message: newValue});
  },
  render: function() {
    var valueLink = {
      value: this.state.message,
      requestChange: this.handleChange
    };
    return <input type="text" valueLink={valueLink} />;
  }
});

As you can see, ReactLink objects are very simple objects that just have a value and requestChange prop. And LinkedStateMixin is similarly simple: it just populates those fields with a value from this.state and a callback that calls this.setState().

ReactLink Without valueLink #

var LinkedStateMixin = require('react-addons-linked-state-mixin');

var WithoutLink = React.createClass({
  mixins: [LinkedStateMixin],
  getInitialState: function() {
    return {message: 'Hello!'};
  },
  render: function() {
    var valueLink = this.linkState('message');
    var handleChange = function(e) {
      valueLink.requestChange(e.target.value);
    };
    return <input type="text" value={valueLink.value} onChange={handleChange} />;
  }
});

The valueLink prop is also quite simple. It simply handles the onChange event and calls this.props.valueLink.requestChange() and also uses this.props.valueLink.value instead of this.props.value. That's it!