React components

ReactJS is based on the idea that the page can be decomposed into basic components, which are called for rendering parts of the page.

For example, if you want to display a list of runs, you can create a Run class that is in charge of rendering a single run given its values, and a Runs class that iterates through a list of runs, and call the Run class to render each item.

Each class is created with the React.createClass() function, which receives a mapping containing the future class methods. The ;createClass() function generates a new class, and sets ;a props attribute to hold some properties alongside the provided methods.

In the following example, in a new JavaScript file we define a Run class ; with a render() function, which returns a <div> tag, and a Runs class:

    var Run = React.createClass( { 
render: function() {
return (
<div>{this.props.title} ({this.props.type})</div>
);
}
} );

var Runs = React.createClass( {
render: function() {
var runNodes = this.props.data.map(function (run) {
return (
<Run
title= {run.title}
type= {run.type}
/>
);
} );
return (
<div>
{runNodes}
</div>
);
}
} );

The Run class returns in a div this value: {this.props.title} ({this.props.type}), which is rendered by visiting the props attribute in the Run instance.

The props array is populated when the Run instance is created, and that is what happens in the render() method of the ;Runs class. The runNode variable iterates through the Runs.props.data list, which contains a list of runs.

That is our last piece of the puzzle. We want to instantiate a Runs class, and put a list of runs to be rendered by React ;in its props.data list.

In our Runnerly app, this list can be provided by the microservice that publishes runs, and we can create another React class, which loads this list asynchronously using an Asynchronous JavaScript and XML (AJAX) pattern via an HxmlHttpRequest class.

That is what happens in the loadRunsFromServer() method in the following example. The code calls the server to get the data by making a GET request on the URL set in the props, and sets the value of props.data by calling the setState() method.

    var RunsBox = React.createClass( { 
loadRunsFromServer: function() {
var xhr = new XMLHttpRequest();
xhr.open('get', this.props.url, true);
xhr.onload = function() {
var data = JSON.parse(xhr.responseText);
this.setState( { data: data } );
} .bind(this);
xhr.send();
} ,

getInitialState: function() {
return {data: []} ;
} ,

componentDidMount: function() {
this.loadRunsFromServer();
} ,

render: function() {
return (
<div>
<h2>Runs</h2>
<Runs data= {this.state.data} />
</div>
);
}
} );

// this will expose RunsBox globally
window.RunsBox = RunsBox;

When the state changes, it triggers the React class to update the DOM with the new data. The framework calls the render() method, which displays the <div> containing Runs. The Runs instance, and then each Run instance, are handed down in a cascade.

To trigger the ;loadRunsFromServer() ;method, the class implements the componentDidMount() method, which gets called once the class instance is created and mounted in React, ready to be displayed. Last, but not the least, the ;getInitialState() ;method is called on instantiation, and can be used to initialize the instance of the ;props attribute with an empty data array.

This whole process of decomposition and chaining may seem complicated, but once in place, it is quite powerful, because it allows you to focus on rendering each component and letting React deal with how to do it in the most efficient way in the browser.

Each component has a state, and when something changes, React first updates its own internal representation of the DOM--the virtual DOM. Once that virtual DOM is changed, React can apply the required changes efficiently on the actual DOM.

All the JSX code we've seen in this section can be saved in a JSX module, and used in an HTML page as follows:

    <!DOCTYPE html> 
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Runnerly Dashboard</title>
</head>
<body>
<div class="container">
<h1>Runnerly Dashboard</h1>
<br>
<div id="runs"></div>
</div>
<script src="/static/react/react.js"></script>
<script src="/static/react/react-dom.js"></script>
<script src="/static/babel/browser.min.js"></script>
<script src="/static/runs.jsx" type="text/babel"></script>
<script type="text/babel">
ReactDOM.render(
<window.RunsBox url="/api/runs.json" />,
document.getElementById('runs')
);
</script>
</body>
</html>

The RunsBox class is instantiated with the /api/runs.json URL for this demo, and once the page is displayed, React calls that URL, and expects to get back a list of runs, which it passes down to the Runs and Run instances.

Notice that we have used window.RunsBox instead of RunBox, because the Babel transpiler does not expose the global variables from the runs.jsx file. That is why we had to set the variable as an attribute of the window variable so it could be shared between the ;<script> sections.

Using transpiration directly into the browser is a bad idea. It is much better to transpile your JSX files beforehand, as we will see in the next section.

This section described a very basic usage of the ReactJS library, and did not dive into all its possibilities. If you want to get more info on React, you should try the tutorial at https://facebook.github.io/react/tutorial/tutorial.html as your first step. This tutorial shows you how your React components can interact with the user through events, which is the next step once you know how to do some basic rendering.

Now that we have the basic layout for building a React-based UI, let's see how we can embed it in our Flask world.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset