ReactJS: An Extended Hello World Example In 8 Minutes or Less

It’s often difficult to get started with a new software library or framework; it seems like there are always a mass of concepts, paradigms, and conventions to learn in any new technology. This post gathers together an extended “Hello World” example implemented using the React library, demonstrating a number of the core features of React.

Here’s the full demo code with key points marked with numbered comments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>ReactJS: Hello World Demo</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <style type="text/css">
        #approot {
            font-family: Verdana, Verdana, Geneva, sans-serif;
            font-size: 24px;
            line-height: 30px;
            padding: 20px;
        }
    </style>
</head>
<body>
 
<!-- 1 -->
<div id="approot"></div>
 
<script type="text/babel">
    class SayHello extends React.Component {  // 2
        constructor(props) {                  // 3
            super(props);                     // 4
            this.state = {name: props.name};  // 5
        }
 
        render() {                            // 6
            return (
                <div className="hello">
                    Hello, {this.state.name}!
                </div>
            )
        }
    }
 
    ReactDOM.render(                          // 7
        <SayHello name="World" />,
        document.getElementById('approot')
    );
</script>
<!-- 8 -->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</body>
</html>

Here’s the breakdown of what is happening in each step:

Step 1: provide a “root” for the app, a location where the content of the app will be placed. It can be any part of typical web page markup: a div, a span, a heading if you want. The markup generated by the React code can coexist perfectly fine with any surrounding static content on the web page. The standard boilerplate code for React apps uses the very generic “getElementById()” DOM API call to find the root element in which to place the app content, but any way of finding the DOM element (like a jQuery selector) will do.

Step 2: Define an ES6 class (named “SayHello” for this example) for the React component that will display the content. This is the root component of the React application, the only component used for this example. Extending from the built-in class “React.Component” allows the class to use features of React. In practice, for real apps, there will be multiple components, often nested within one another, each specialized to display one feature of the total web app.

Step3: Define a constructor for the component class, taking one “props” argument. Any attributes specified on the “<SayHello />” markup later will come in as properties of this “props” argument (for this demo, there is one “name” attribute on the SayHello tag that will show up as “props.name” in the constructor).

Step 4: Call super(props) to pass the props argument up to the React.Component superclass of the component class. The call to super() is required if you’re going to reference ‘this’ in your component – by ES6 spec, “this” will not be initialized (will be undefined) if super() is not called.

If “super()” isn’t called at all, you’ll see an error like “‘this’ is not allowed before super()” in the browser dev console.

Step 5: Create an object literal and assign it to the “state” data member of the component class. According to the React documentation, the “props” property of the component is frozen (using ECMAScript5 Object.freeze()) to prevent properties from being added, removed, or modified from their initial values that came in from attributes of the component’s DOM tag.

You’ll get an error like “Cannot assign to read only property ‘name’ of object” if you try to change the “props” object.

Properties of the state object can be changed, and a change in state forces a redisplay of the component. For the redisplay to happen, you have to follow the protocol of calling “this.setState({prop: value})”; simply assigning the property of the state object to a new value won’t do anything.

There’s a lot of thought behind how state should be used and changed in React. See the discussion of “state data flows down” on the ReactJS site for a discussion of correct ways to manage state in React applications.

Step 6: define a render() method that creates some DOM elements that are to be displayed for the component. This is where the real “magic” happens in React: any kind of standard HTML markup can be added and merged with data from the component and its state (“this.state”) properties. This combined HTML and code syntax used in the render methods in React is called “JSX”. The markup is compiled into regular HTML by the JSX compiler that’s built in to React.

Two details to notice in this render() method: first, the outer div that wraps the markup has been given a CSS class, “hello”. JSX markup uses a “className” attribute rather than the “class” attribute that’s used in HTML (this is actually a reference to the “className” property of a DOM element). In the final compiled markup that is sent to the browser, any “className” attribute on an element does become a standard “class” attribute. Putting CSS classes in critical locations can provide ways to style the component independently of the code.

The second notable detail in the render() method is that the value of the “name” property of the component’s “state” data member is inserted into the component’s markup using curly braces, “{this.state.name}”. This is the way that dynamic data gets displayed by the component. Curly braces can contain general Javascript expression syntax, like iteration over a loop to generate multiple DOM elements (see the example below).

Step 7: Call the top level “ReactDOM.render()” method. The first argument is some JSX markup that uses the component class name as a tag (like “<SayHello />”). The second argument is a reference to the DOM element where that markup is supposed to be displayed (found with “document.getElementById()”). Like the render() method of a component, this ReactDOM render() method accepts JSX as its content, in this case a simple reference to the component that was defined earlier. The target DOM element is found with a call to the standard document.getElementById(), but it could be any other code that finds a valid DOM element, such as document.querySelector().

Step 8: import the libraries for react.js and react-dom.js as well as the Babel compiler for ES6 transpilation.

The Flow of the Code

It’s important to understand the flow of the code, which is the opposite order from the way things are declared in the example markup:

  1. The ReactDOM.render() is called; it compiles the JSX markup that is passed to it and inserts the resulting markup in the DOM element that was found with document.getElementById()
  2. The JSX Markup refers to one or more components by HTML tag name (“SayHello” here). The React library looks for an ES6 class with that name (there is also an alternate syntax that could be used to define a component using a function)
  3. React creates an instance of a component class for each component tag in the JSX
  4. The constructor of the component class is called, passing the “props” argument which has the names and values of all attributes that are present in the JSX markup (just one attribute, “name”, in this case)
  5. The code in the constructor saves the values of the properties in the “state” data member of the component class
  6. The component “render()” method is called, which renders any JSX markup given in that method, inserting the values of any Javascript expressions that are enclosed in curly braces (“{…}”)

Two More Things to Make it Real

This simple “hello world” application is a good start, but some other pieces have been left out to keep the demo a reasonable size. Here are two more kinds of features that you’ll likely have to implement to create a production application:

  • Adding interactivity with “onEventName” handlers
  • Loading data from an external source (using AJAX or GraphQL or something similar)

First, interactivity: handling events from users interactions. In React, an attribute like “onClick” (or “onMouseOver”, “onMouseOut”, etc) is used to attach a Javascript function to any markup in the JSX code of a component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class SayHello extends React.Component {
    constructor(props) {
        super(props);
        this.state = {name: props.name};
        // 1. Declare the event handler using an arrow function
        this.clickHandler = () => e => { alert("You clicked, " + this.state.name + "?"); };      }
    render() {
        return (
            <!-- 2. Attach the click handler here using "onClick" -->
            <div onClick={this.clickHandler()} className="hello">                Hello, {this.state.name}!
            </div>
        )
    }
}

By convention, event handler functions are declared outside the JSX code (chiefly for reusability). In the above example the click handler is declared in the constructor as an arrow function. An arrow function is useful here because it implicitly binds to its surrounding scope (eliminating the need for an explicit call to .bind(this)). See my recent post ECMAScript 6 Functions and Function Scope as well as the React documentation on Handling Events for more information on this.

The second feature is loading data from an external API. For this example, I’m using AJAX with the Axios library (Axios is simple yet full-featured AJAX library can be loaded as one file from a CDN).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class SayHello extends React.Component {
    constructor(props) { ... }
 
    componentDidMount() {    // 1. Implement the componentDidMount() lifecycle method        let dataPath = "data/mydata.json";
        axios.get(dataPath)    // 2. Load data via AJAX            .then( res => {
                const data = res.data;
                this.setState({ data });  // 3. setState() to force an update            })
            .catch( err => {
                let resp = err.response;
                alert("Error loading data: " + resp.status + " " +
                    resp.statusText + ": " + resp.config.url);
            });
    }
 
    render() {
        return (
            <div>
                <!-- 4. Use the data -->
                {this.state.data.map(data =>                    <MyDataItem data={data.value} key={data.id} />                )}            </div>
        );
    }
}
 
...
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>

The pattern in loading external data is to:

  • Implement the componentDidMount() lifecycle method
  • Call the .get() method of the AJAX library class of your choice to get the data (or .post() if required by the API)
  • Call setState() on the received data to store it in the component – this also initiates a render update
  • Use the data in curly braces in the JSX of the component render() method

Notice that a “key” attribute is set for the data item components that are created from the data. For React to display a list of components efficiently, it needs a unique key for each element to track which ones have changed. This value can be obtained from any unique id associated with the item data (like a key from a database).

An alternate library for loading data via AJAX, Fetch, is widely used in the React community. It was not used in this demo because it has multiple dependencies that make it more usable in a production webpack project rather than a loading it via CDN URL for a simple demo like this. Both Axios and Fetch honor the same standard “promises” interface (then(), catch()) for requesting and using AJAX data.

TL;DR

A React app is a collection of nested components that are arranged using HTML-like tags (JSX) in the render() methods of components. The top of the hierarchy of components is located in a call to the ReactDOM.render() class. The HTML syntax is placed directly in the body of each component’s render() method and is compiled into HTML.

Data may be passed between components using attributes of the component tags. This data appears as properties of a “props” argument to the constructor of each component’s corresponding Javascript class (or function) implementation.

Interactive events are handled in a React component by specifying “on” attributes to the component’s tag (like “onClick()”) that refer to a Javascript function implemented in the component’s Javascript class.

Data can be loaded asynchronously (with “AJAX” or similar technology) and displayed in components by making a call to “this.setState()” on the component in the async data completion (“then()”) method. The call to “this.setState()” forces a re-rendering of components (simply setting properties on “this.state” in the component does not make the component render again).

Want to experiment with this example? There’s a codepen available with the example from this post.

References

The Introducing JSX page on the React site gives a lot more information on how JSX is used to create web applications.

The React documentation is really very approachable, an excellent resource for learning the details of working with React. It’s divided into “Quick Start”, “Advanced Guides”, and “Reference” sections, each with a number of short articles, each on an individual topic. Check this out for more information on topics discussed in this post!

See in particular the discussion of Axios AJAX library, or install the package with ‘npm’ or ‘yarn’ and read the Readme.md and source code:

$ npm install axios
...
$ yarn add axios

Information on the fetch AJAX library, or install the package with ‘npm’ or ‘yarn’:

$ npm install fetch
...
$ yarn add fetch

Versions

React v16.0
Babel v6.15.0
Axios v0.18.0

Add a Comment

Your email address will not be published.