Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Beginning ReactJS By Example

5.00/5 (1 vote)
26 Jan 2018CPOL10 min read 14.6K   348  
Learn ReactJS with a simple drop down UI element example.

Introduction

I recently read a statistic that indicated that ReactJS has quickly become one of the mostly popular web front-end technologies. Therefore, as a software developer by trade, I thought it was time to learn it.

The first thing you will notice when learning ReactJS is that it is component-based; i.e., a ReactJS app, including the app itself, is made up of components. Therefore, I figured the most logical type of component to create with the new technology would be some type of UI component or widget. In the past, I have created UI widgets purely in JavaScript or TypeScript that mimic existing HTML elements but are easier to work with (particularly in JavaScript). So, I decided to create a “ListBox” (or “DropDown box”) based on the HTML select element.

The next thing you should understand about ReactJS is that, while not strictly necessary, it commonly takes advantage of a technology called JSX. JSX is an XML-like syntactic extension to JavaScript that allows you to embed UI markup inside JavaScript. The primary advantage of this is that it allows the UI markup and associated logic to be embedded in the same component which, as stated above, fits in nicely with the component-based model of ReastJS. While I won't go into detail about JSX since it is a separate technology, I have mentioned it here because it is used in the example below.

Another aspect of ReactJS development that should be noted is that it takes advantage of the latest JavaScript specification EMCAScript 6. Because of this and the integration with JSX, it commonly needs a transpiler like Babel to convert the application into plain EMCAScript 5 JavaScript code. I won't go into detail about configuring your development environment for ReactJS either.

Let's now jump into the code to get into the details of how ReactJS works and the benefits it provides in making front-end development easier.

Components

A component is commonly created by using the class syntax for EMCAScript 6 and extending (also known as 'inheriting' in object-oriented parlance) from the React.Component class, as follows:

JavaScript
class App extends React.Component
{
}

Of course, we can name this class anything we want but by naming this particular class 'App', it becomes rather obvious that this is our 'application' component representing the highest level component for our application. To “start” the application, you then just need to call the render method on the ReactDOM class and pass in your application component and the HTML element where it will render to, as follows:

JavaScript
ReactDOM.render(<App />, document.getElementById('content'));

All components within the application component will then be automatically rendered by calling the 'render' method on each one; therefore, you are required to create a 'render' method for each component your create. This 'render' method is where you define the UI layout of your component and generally consists of standard HTML elements combined with JSX elements. Below is the render method of our application class where the two ListBox elements are JSX elements based on our new ListBox component.

JavaScript
render()
{
    return (
        <div>
            <h1>Car Selection</h1>
            <ListBox Items={this.state.carMakes}
                     valuePropertyName='id'
                     selectedValue={this.state.selectedMake}
                     placeholder='Please select a make...'
                     textPropertyName='name'
                     OnSelect={this.OnCarMakeSelect} />

            <ListBox Items={this.state.carModels}
                     selectedValue={this.state.selectedModel}
                     placeholder='Please select a model...'
                     OnSelect={this.OnCarModelSelect} />

         </div>
    );
}

In this example, the top-level element for our application (ignoring the element where we are placing the application component on the page) is a 'div' element that consists of an 'h1' element plus two ListBox components.

Properties

As you can see, we can define any number and type of attributes on a JSX element and assign values to them. These elements become “properties” on the corresponding child components. Note that in order to include JavaScript code in the JSX syntax, you must enclose it in curly brackets.

Now we will take a look at the ListBox component definition with its render method to see how the attributes defined in the component declaration are accessed.

JavaScript
class ListBox extends React.Component
{
    render()
    {
        return (
            <div className="listBox">
                <select onChange={this.OnChange.bind(this)} ref='listBox'>
                    <option value="-1" disabled selected hidden>{this.props.placeholder}</option>
                    {this.props.Items.map((item, i) =>
                    <ListBoxItem Item={{ 'Text': item[this.textPropertyName],
                    'Value': item[this.valuePropertyName] }} />)}
                </select>
            </div>
        );
    }
}

You will immediately notice that the attributes assigned to the component are accessed using an object named 'props' which is automatically created for you. As I mentioned in the beginning of this article, our listbox is based off the 'select' HTML element and this is where it is defined. Although it doesn't provide much of a benefit in our list box component, I have also created a ReactJS component for each 'option' element, represented by the ListBoxItem component, defined below:

JavaScript
class ListBoxItem extends React.Component
{
    render()
    {
        return (
                <option key={this.props.Item.Value}
                value={this.props.Item.Value}>{this.props.Item.Text}</option>
        );
    }
}

We pass down two values (via attributes) to each ListBoxItem component representing the value and text of each option HTML element. It is recommended that we add a 'key' attribute whenever the component represents an item in a list as this attribute is used by ReactJS to identify which items have changed, have been added or have been removed.

It should be obvious by now that our list box component is rendered simply as a 'select' HTML element.

Though it is not related to ReactJS specifically, it should be noted that the first option element we define in the listbox is a way to provide placeholder text for the select HTML element since the select element does not have a standard 'placeholder' attribute. We also use it as a way to default the listbox to have no option selected when it is first rendered.

It is also worth noting here that this ListBox component provides a way to 'declare' the name of the properties on the objects in the Items list that represent the 'value' and 'text' properties of each option element. As you can see in the code below this is easily implemented using one of the ways in JavaScript to access fields on objects in an array by using brackets:

JavaScript
<ListBoxItem Item={{ 'Text': item[this.textPropertyName],
'Value': item[this.valuePropertyName] }} />

Now, let's get back to ReactJS.

State

One of the major benefits of ReactJS is how state is handled. Maintaining and manipulating state in any application can be cumbersome and make it difficult to debug. It is recommended that state be maintained at the highest level possible which is typically in the application component. When developing a component like our list box, it is tempting to put some type of state in the ListBox component itself; for example, for keeping track of the currently selected item (or value) in the listbox. However, in this case, the ReactJS way of doing this is to store the currently selected item in the application state.

State for each component should be stored in an object named 'state' and state is manipulated using a method named 'setState' (which updates the state object). Here is the state as it is initially defined in our application component:

JavaScript
this.state =
{
    carMakes: GetCarMakes(),
    selectedMake: -1,
    carModels: [],
    selectedModel: -1
}

GetCarMakes() is just a JavaScript function outside of our component that returns an array of car makes. carModels is a state property initially defined as an empty array and will be manipulated each time a new make is selected.

selectedMake and selectedModel are the two properties used to store the currently selected make and model from the corresponding ListBox components. It makes sense that these are tracked in the application component since, at some point, we will likely save these selections to some type of back-end store along with other data.

In ReactJS, it is recommended that state be immutable where, for example, instead of modifying an array directly, the array is recreated each time it changes. This is done by calling the 'setState' method. The nice thing about this method is that you only need to 'set' the properties that are changing – any other existing state properties remain as part of the state. As an example, have a look at the code for our OnCarMakeSelect method of our application component:

JavaScript
OnCarMakeSelect(value, text)
{
    this.setState({ selectedMake: value, carModels: GetCarModels(value), selectedModel: -1 });
}

We will discuss events and event handlers in a minute but just know that this method is called every time a new car make is selected. In that case, we update the currently selected make and the array of car models (as well as setting the currently selected model to -1 so no default option is selected in the models ListBox and the placeholder is displayed).

Binding

This is the appropriate time to talk about binding in ReactJS. No JavaScript library or framework that interacts with UI would be complete with some type of binding. Unfortunately, while many of these libraries (e.g., KnockoutJS) provide two-way binding, ReactJS only provides one-way binding. The direction of this binding being from state to UI with no corresponding binding from UI back to state. In other words, you need to handle updating the state whenever something changes in the UI, which is generally done with DOM events combined with event handlers.

State is bound to components declaratively where the component is declared. For example, as we saw above:

JavaScript
<ListBox Items={this.state.carMakes}
         valuePropertyName='id'
         selectedValue={this.state.selectedMake}
         placeholder='Please select a make...'
         textPropertyName='name'
         OnSelect={this.OnCarMakeSelect} />

<ListBox Items={this.state.carModels}
         selectedValue={this.state.selectedModel}
         placeholder='Please select a model...'
         OnSelect={this.OnCarModelSelect} />

this.state.carMakes and this.state.selectedMake are bound to the first ListBox and this.state.carModels and this.state.selectedModel are bound to the second one.

As part of the binding process, one of the more powerful functions of ReactJS is its ability to determine, based on changes to state, which components need to be re-rendered (it is my understanding it is JSX that makes this easier). This makes ReactJS more efficient than other JavaScript libraries. This process is performed whenever the 'setState' method is called. For example, in the OnCarMakeSelect method shown above since the carModels and selectedModel state properties are 'bound' to the car models ListBox component that component will automatically be updated (i.e., re-rendered).

Events and Event Handlers

As I mentioned above, DOM events and event handlers are required to handle binding from the UI back to your state. The preferred way to do this is by sending event handler functions to your child components as properties and update the state (and do whatever else) inside the component where you are storing the state. In our example, we have created two event handler functions in the application component as follows:

JavaScript
OnCarMakeSelect(value, text)
{
    this.setState({ selectedMake: value, carModels: GetCarModels(value), selectedModel: -1 });
}

OnCarModelSelect(value, text)
{
    this.setState({ selectedModel: value });
}

Notice we defined two parameters for each of these functions. We pass these functions to the ListBox child components through a property that we named OnSelect, as follows:

JavaScript
<ListBox Items={this.state.carMakes}
         valuePropertyName='id'
         selectedValue={this.state.selectedMake}
         placeholder='Please select a make...'
         textPropertyName='name'
         OnSelect={this.OnCarMakeSelect} />

<ListBox Items={this.state.carModels}
         selectedValue={this.state.selectedModel}
         placeholder='Please select a model...'
         OnSelect={this.OnCarModelSelect} />

In the ListBox component, we have created a handler function that is called from the onChange event from the select HTML element. This function is below:

JavaScript
OnChange(event)
{
    this.props.OnSelect(event.target.value,
                        event.target.options[event.target.selectedIndex].text);
}

So, we take the data from the DOM event that is passed by default into this handler function and pass the selected value and associated text from the selected item in the select element to the parent event handler assigned to the OnSelect property. (This way, the parent component doesn't need to understand or worry about what a DOM event is.)

That's all there is to it except for one thing. You may have noticed the following code in the constructor method of the application component:

JavaScript
this.OnCarMakeSelect = this.OnCarMakeSelect.bind(this);
this.OnCarModelSelect = this.OnCarModelSelect.bind(this);

Since class methods are not bound by default in JavaScript, you must bind the this object instance to each method that you pass to a component; otherwise, the this property will be undefined when it is eventually called.

The final aspect of ReactJS that is part of this example and that I haven't discussed yet is the concept of the component life cycle. Each component has a life cycle whereby certain events can be handled at different stages of initializing and rendering and you can implement methods to inject your own logic at these different stages. I will leave it up to the reader to research the different events/methods, but I will explain the one we implement in our example. Below is the code for this event handler:

JavaScript
componentDidUpdate(nextProps, nextState)
{
    var select = this.refs.listBox;
    if (select)
    {
        select.value = this.props.selectedValue;
        this.props.OnSelect(select.value);
    }
}

The componentDidUpdate is called just after every render. We implement this in our example because the car models list can change depending on the make selected and we want to reset the selected value (to -1 if we want no selected value when the list changes). Note the use of the 'refs' property. This is a nifty ReactJS property that allows you to reference the DOM element for any of the DOM elements defined in the component. This is used in tandem with the 'ref' attribute that can be defined on each DOM element.

Conclusion

I hope, by this rather small example, that I have hit upon the important concepts of ReactJS and that this will give you a major head start with ReactJS development.

History

  • 01/25/2018 - Initial upload

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)