Search Interface with React js
We’ll place a new index.html file inside the public folder that QEDServer created for us when we started it up. In this file, we place our usual HTML skeleton and a
element that will hold our application. We’ll tell React to render its contents into this area of the page. We also import a few libraries in the header section of the page:
react/index.html
We’re including React, but we’re going to use jQuery for making our Ajax requests. React is purely a UI library; it doesn’t have its own way of fetching data from servers. The third library we’re loading is React’s JSX Transformer. React has its own dialect of JavaScript, called JSX, that makes creating templates easier. Let’s start by creating the outer component. In search.js, we create the initial version of our ProductSearch component: react/search.js Product Search Waiting…
var ProductSearch = React.createClass({ render: function() { return ( The preceding code doesn’t do too much other than render a ); } });Product Search
with an inside. But it won’t actually render the component until we tell React to render it, like this:
React.render(
inside. But it won’t actually render the component until we tell React to render it, like this:
React.render( , document.getElementById(‘content’));
react/search.js
var ProductSearch = React.createClass({
getInitialState: function() {
return {data: []};
},
react/search.js
var ProductSearch = React.createClass({
componentDidMount: function() {
$.ajax({
url: ‘/products.json’,
dataType: ‘json’,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
Now we can render the list of products. We alter the ProductSearch component’s render method by adding in our ProductList component, passing the data as an attribute:
react/search.js
render: function() {
return (
Product Search
{ /* START_HIGHLIGHT */ }
);
}
Finally, we define the ProductList component, which renders the data. The data was passed in as an attribute called data, so to access it inside the ProductList component we use this.props.data. Any attributes passed to a component become its properties. We use properties to pass data around our components, and we use this.state to manage the component’s internal data that should trigger rendering.
Our list of products will be an HTML table, with the results displayed as the table rows. So our ProductList component ends up looking like this:
react/search.js
var ProductList = React.createClass({
render: function() {
var products = this.props.data.map(function (product) {
return (
{product.name}
{product.description}
{product.price}
);
});
return (
Name Description Price
{products}
);
}
});
We first take the data stored in the component’s props and transform it into an array of table rows by using JavaScript’s map function. Then we return an HTML table that contains those rows. This pattern is common in rendering collections of data in React. You construct the inner part first and then wrap it with the outer parts of the component.
When we refresh the page in the browser, we see our list of products, as in the figure.
The outer component is rendering the inner component, passing it data. The inner component doesn’t need to know where it got its data from; it’s completely decoupled. That means we can send it data we get from a search query, rather than the most recent data. So let’s build the search feature.
Adding the Form
Our ProductSearchForm will contain the HTML form that visitors will use to perform the search. The outer component, ProductSearch, is responsible for talking to our back end, but we have to put the code that handles the form submission inside the ProductSearchForm component. So we’ll make the submit handler in ProductSearchForm delegate to a function that we declare in the ProductSearch component. The following diagram explains how this will work:
When we render the form, we’ll pass a reference to the getSearchResults function into the ProductForm component. So, let’s build the ProductForm component first and get it rendering. We’ll wire it up later.
The form itself ends up being another component with a render function that returns an HTML form. However, we can add a few important pieces to the markup. We use the ref attribute to name a form field so we can easily locate it later. And we attach the function that will handle the form directly to the form by using the onSubmit attribute:
react/search.js
var ProductSearchForm = React.createClass({
render: function(){
return (
);
}
});
Then, when the form is submitted, we have to capture the submission event and prevent its default behavior. Then we get the value from the form by using this.refs and referencing the ref we gave our form field, which was query:
react/search.js
var ProductSearchForm = React.createClass({
sendSearchQuery: function(e){
e.preventDefault();
var query = this.refs.query.getDOMNode().value.trim();
},
In ProductSearch, we render the search form, passing in the callback function:
react/search.js
render: function() {
return (
Product Search
{ /* START_HIGHLIGHT */ }
);
}
And then in ProductSearchForm’s sendSearchQuery method we add a line of code that invokes the callback, passing it the query. Since we pass it in to the component, we access it via this.props, as we did when we accessed the data we wanted to display:
react/search.js
sendSearchQuery: function(e){
e.preventDefault();
var query = this.refs.query.getDOMNode().value.trim();
this.props.onSearchRequest(query);
},
All that remains is to declare the getResults method in the ProductSearch component. This method looks almost identical to the method that we used to display our initial data from the server, but it sends the request to /products.json?q= followed by the search query:
react/search.js
getResults: function(query){
$.ajax({
url: ‘/products.json?q=’ + query,
dataType: ‘json’,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
And with that, we have a complete search page, driven by React
);
}Product Search
{ /* START_HIGHLIGHT */ } Name | Description | Price |
---|
);
}
Comments
Post a Comment