React Tutorial A Step-by-Step Guide(4) — Rendering Elements and Handling Events

Kasun Dissanayake
7 min readNov 22, 2022

--

In this tutorial, I am going to explain more features of React using my sample project. Please refer to my previous article if you missed the first part of the Sample Shopping Cart Application creation.

How to set Attributes on the elements

Let's apply some styles to the span element. For that, you need to add a class attribute to the span element. But it is not the “class” attribute. It is “className” because it is defined in JSX and we had to use that as className. Inside “className” I am going to use a couple of bootstrap classes.

Add some styles to the button element also.

<span className="badge bg-primary m-2"> {this.checkCount()} </span>
<button className='btn btn-success btn-sm'>Increment</button>

Then run the code and check your browser. You will get a UI like this.

Rendering Classes Dynamically

Let's change the color of our count badge dynamically. If the count is zero let's change the color of the badge to yellow(like a warning message) otherwise we can show it in blue color. So we can change it using our classes.

badge bg-primary — Normal message to show the count

badge bg-warning — As a Warning message if the count is zero

So that we need to render one of these classes dynamically depending on the value of the count property. We can define a variable inside our Cunter class and depending on the value of the count we can change it.

  1. Define a variable called classes.
let classes = "badge m-2 bg-"

2. Change the value of the variable depending on the count.

classes += (this.state.count === 0) ? "warning" : "primary";

3. Add this class variable inside the span “className”.

<span className={classes}> {this.checkCount()} </span>

Save the changes, Run and check the browser.

Initially, our count is zero. That is why we are getting this yellow badge. Check the UI by changing your count variable value to a non-zero value. You will get a blue color badge.

You can encapsulate this implementation inside a function. It will help other developers to understand the code and change the code. Then call the function inside the span attribute.

getBadgeClasses() {
let classes = "badge m-2 bg-";
classes += (this.state.count === 0) ? "warning" : "primary";
return classes;
}

Rendering Lists

In this section, we are going to learn How to render a list of Items. Let's imagine you want to render a list of tags. For that, you need to add a new property to a state object called tags, and should be an array. Now you can render these tags using <ul> and ><li> elements. If you have worked with angular you have seen the ngFor directive to use, if we want to display a dynamic list in a loop. But in React in JSX expressions we don't have the concepts of loops because JSX is not a templating engine, just a simple syntax that will eventually get compiled to React elements.

How we can render a bunch of list items then?

We can use the map method of arrays. We can use the map method to map each and every element in this array into a react element. Now we can render the list of items.

For the argument, we need to pass an array function.

{this.state.tags.map()}

Each tag map to the list item. This is basically getting a string and mapping it to the JSX expression.

<ul>
{this.state.tags.map(tag => <li> {tag} </li>)}
</ul>

Now you see the output as this in the browser.

However, you will get an error in the browser console saying like,

It means that React needs a unique key to uniquely identify each and every element in the list because of the state of the react element. When the virtual DOM changes React quickly figures out what element is changed and where in the DOM it should make changes to keep the DOM unsafe with the Virtual DOM.

Now we can add the key value to our list. For the value of the key, we can use a unique id for it. Here I am using ‘tag’ as the unique id.

<ul>
{this.state.tags.map(tag => <li key={ tag } > {tag} </li>)}
</ul>

Conditional Rendering

Now we have an array of items. We are rendering that in a list. If we want to add a condition here what do we do? Unlike Angular, we don't have if and else in JSX. Assume we need to show a message or a text if there are no elements in the list(tags) otherwise we need to render the array with elements. This is the simplest way to implement that. To render elements conditionally we need to go back to javascript. We can add a separate hyper method called renderTags() and inside that, we can implement the logic. Inside the render() method you need to call this renderTags method.

renderTags(){
if( this.state.tags.length === 0) return <p>There are no tags!</p>
return <ul> {this.state.tags.map(tag => <li key={ tag } > {tag} </li>)} </ul>;
}

Here if the array is not empty we are just rendering the whole elements of the array. Otherwise, we are showing a message like “There are no tags!”.

 render() { 

return (
<div>
{this.renderTags()}
<div>
);
}

Handling Events

All these react elements have events. We can fire an event for the user activity. As an example button has many events like OnClick, DoubleClick, onDoubleClickCapture, and so on. You can implement a separate target function for executing after firing the event.

Target function to log the console when we click the button.

handleIncrement(){
console.log('Increment Clicked');
}

In the button attribute, you need to pass the reference to the method.

<button onClick={this.handleIncrement} className='btn btn-success btn-sm'>Increment</button>

Now let's click the button, and you will get an output message as ‘Increment Clicked’.

Output Console

Binding Event Handlers

Now I am going to increment the value of the count property when clicking the Increment button. We can increment the count property inside the target function. But you might get an error like this when we add this keyword in the target function.

Error log

The issue is ‘this’ is undefined. So that you cannot access the state properties because of this problem. This is because JavaScript behaves differently compared to other languages. Depending on how the function is called this can refer to different objects. The “Cannot read property ‘props’ of undefined” error occurs when a class method is called without having the correct context bound to the this keyword. To solve the error, define the class method as an arrow function or use the bind method in the class's constructor method.

Notice that we defined the handleIncrement method, but we haven't bound the context of the this keyword.

Therefore, the this keyword in the handleIncrementmethod has a value of undefined.

  1. Manually bind Event Handlers

We can add a constructor( this is a method that we called when the Object of the class was first created). In the constructor, we do have access to this keyword(You can put a console log and check inside the constructor). Inside the constructor method you need to call the constructor of the parent class using the super method because ‘this’ is not allowed before the super() method.

constructor(){
super();
console.log(this);
}

Now you can use the bind method and it will return a new instance of handleIncrement function and in that function, this is always referencing the current object. Now we can reset the handleIncrement function by a new instance like this.

constructor(){
super();
this.handleIncrement = this.handleIncrement.bind(this);
}

Now you can access the state property without getting any error.

2. Use Arrow functions

In the previous option, we have to implement code for each and every event handler and that is not easy and impacted the code quality. We can convert the handleIncrement function into an arrow function.

handleIncrement = () =>{
console.log('Increment Clicked' , this.state.count);
}

This works because arrow functions use the this keyword of the enclosing scope - in our example, the enclosing scope is the specific component instance.

I hope you get a better understanding of rendering elements and handling events in React. We will learn how to update the state dynamically and pass event arguments in the next tutorial.

Thank You!

--

--

Kasun Dissanayake
Kasun Dissanayake

Written by Kasun Dissanayake

Senior Software Engineer at IFS R & D International || Former Software Engineer at Pearson Lanka || Former Associate Software Engineer at hSenid Mobile

No responses yet