We will discover this technique by creating a searchable list component.
For the List
to be able to display only the ListItem
s which match the filterText
entered in the SearchBar
, we need to pass filterText
back to the parent component SearchableList
. Having the filterText
added to the state of SearchableList
will automatically inform the List
once filterText
changes.
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:
For each piece of state in your application:
- Identify every component that renders something based on that state.
- Find a common owner component (a single component above all the components that need the state in the hierarchy).
- Either the common owner or another component higher up in the hierarchy should own the state.
- If you can’t find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.
Let’s run through this strategy for our application:
List
needs to filter theListItem
s based on state andSearchBar
needs to display the search text and checked state.- The common owner component is
SearchableList
. - It conceptually makes sense for the filter text and checked value to live in
SearchableList
Cool, so we’ve decided that our state lives in SearchableList
. First, add a getInitialState()
method to SearchableList
that returns {filterText: ''}
to reflect the initial state of your application. Then, pass filterText
to List
and SearchBar
as a prop. Finally, use these props to filter the ListItem
s in List
and set the values of the form field in SearchBar
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//[SearchableList.js]
var React = require('react');
var SearchBar = require('./SearchBar');
var List = require('./List');
var SearchableList = React.createClass({
getInitialState: function () {
return({filterText: 'Foo Bar'})
},
render: function () {
return (
<div id='SearchableList'>
<SearchBar filterText={this.state.filterText} />
<List filterText={this.state.filterText} />
</div>
)
}
});
module.exports = SearchableList;
1 | //[SearchBar.js] |
1 | //[List.js] |
You can start seeing how your application will behave: set filterText
to "Foo Bar"
and refresh your app. You’ll see that the data table is updated correctly.
So far, we’ve built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it’s time to support data flowing the other way: the form components deep in the hierarchy need to update the state in SearchableList
.
React makes this data flow explicit to make it easy to understand how your program works, but it does require a little more typing than traditional two-way data binding. React provides an add-on called ReactLink
to make this pattern as convenient as two-way binding, but for the purpose of this post, we’ll keep everything explicit.
If you try to type or check the box in the current version of the example, you’ll see that React ignores your input. This is intentional, as we’ve set the value
prop of the input
to always be equal to the state
passed in from SearchableList
.
Let’s think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since components should only update their own state, SearchableList
will pass a callback to SearchBar
that will fire whenever the state should be updated. We can use the onChange
event on the inputs to be notified of it. And the callback passed by SearchableList
will call setState()
, and the app will be updated.
Though this sounds complex, it’s really just a few lines of code. And it’s really explicit how your data is flowing throughout the app.
in SearchableList.js add the function changeFilterText
and pass it to the SearchBar
component.
1 | //[SearchableList.js] |
inside SearchBar.js call the before passed changeFilterText
inside a wrapper function and assign the wrapper function to the onChange
attribute.
1 | //[SearchBar.js] |
et voilà, this is our two-way data binding.
In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the underlying execution model will automatically propagate changes through the data flow.