Posts

,

Handling Events in React 101

In this article, we will be looking at how to handle events in React. Specifically, we’ll look at how to listen for some of the most common event types. We’ll also look at some of the event properties which you can work with in order to listen for two or more events at the same time. Lastly, we’re going to look at some of the event handling ‘gotchas’ in React.

How to Listen to Events

Not unlike libraries such as jQuery, React has its own event handling system which is called Synthetic Events. Synthetic Events is a cross-browser wrapper of the browser’s native event. It works the same way as the event system that you find on browsers, the only difference is that the same code will work across all browsers.

Click

Here’s an example of how to listen for a click event:

import React, { Component } from 'react';

class ShowAlert extends Component {
  
  showAlert() {
    alert("Im an alert");
  }

  render() {
    return (
      
    );
  }
}

export default ShowAlert;

The onClick attribute is added to the target element in order to specify the function to be executed when that element is clicked. Note that this isn’t limited to just buttons, you can add the onClick attribute on any element or custom component that you create. In the example above, the showAlert() function is executed once the button is clicked. onClick is a type of mouse event.

Change

Now let’s take a look at the onChange event. This is commonly used for text fields to listen for when the user types something in it. Here’s an example of how to update the contents of an element based on the current value of a text field:

import React, { Component } from 'react';

class ChangeInput extends Component {
  
  constructor(props) {
    super(props);
    this.state = {
      name: ''
    };
  }

  changeText(event) {
    this.setState({
        name: event.target.value
    });
  }

  render() {
    return (

{ this.state.name }
); } } export default ChangeInput;

Here we’re adding the onChange attribute to the element which we want to listen for changes in contents. Note that unlike the onClick attribute, you can’t just add this to any element. You can only add it to the input of type text, textarea and select. The current value of the target element is stored in the target.value property of the event object. The event object gets passed as an argument to the function that you passed in to the onChange attribute. In order to update the contents of the h3 element, we update the component’s state with the current value of the text field.

You can find out more about handling events in forms by reading the documentation on Forms in React.

Hover

Next is the hover event. In the example below, the box will change its background color depending on whether its currently being hovered over or not. Just like the previous example, this uses state to update the styles of the box. But instead of one attribute, you need to add two: onMouseEnter and onMouseLeave. Both are pretty self-explanatory, all you have to do is assign the function that changes the default color to the onMouseEnter attribute. And then the function for bringing back the default color to the onMouseLeave attribute.

See the Pen AppendTo: React Events 101 – Hover by Wern Ancheta (@wernancheta) on CodePen.

Here are the codes:

import React, { Component } from 'react';

var styles = {
  box: {
    width: '100px',
    height: '100px'
  },
  in: {
    backgroundColor: 'red'
  },
  out: {
    backgroundColor: 'green'
  }
};

class HoverBox extends Component {
  
  constructor(props) {
    super(props);
    this.state = {
      box_state: 'out'
    };
  }

  changeColor() {
    this.setState({
        box_state: 'in'
    });
  }

  resetColor() {
    this.setState({
      box_state: 'out'
    });
  }

  render() {
    return (
); } } export default HoverBox;

Event Properties

We already know that an event object gets passed to the function that takes care of handling the event. As we’ve seen earlier, there’s the target property which allows us to get the actual element being targetted by the event. If its a text field, the current value can be found on the value property of the target.

Depending on the type of event, there are different properties that you can access in order to further customize how events will be handled. For example, the onClick event is a type of Mouse Event. But we can also use it in combination with other events. One common example of this is the pressing of the Ctrl key on the keyboard while clicking on the files you want to select.

select files

Here’s a React component that simulates that behavior:

See the Pen AppendTo: React Events 101 – Select Boxes by Wern Ancheta (@wernancheta) on CodePen.

Here are the codes:

import React, { Component } from 'react';

var styles = {
  box_container: {
    padding: '20px'
  },
  box: {
    width: '50px',
    height: '50px',
    float: 'left',
    marginLeft: '10px'
  },
  default_box: {
    backgroundColor: 'gray',
  },
  selected_box: {
    backgroundColor: 'orange'
  }
}

class SelectBoxes extends Component {
  
  constructor(props) {
    super(props);
    this.state = {
      boxes: [
        false,
        false,
        false
      ]
    }
  }

  selectBox(index, event) {
    var box_states = this.state.boxes;
    if(!event.ctrlKey){
      box_states = [
        false,
        false,
        false
      ];
    }

    var is_selected = box_states[index];
    box_states[index] = !is_selected;
    this.setState({
      boxes: box_states
    });
  }

  renderBoxes() {
    return this.state.boxes.map((is_selected, index) => {
      let box_type = 'default_box';
      if(is_selected){
        box_type = 'selected_box';
      }
      return (
); }); } render() { return (

{ this.renderBoxes.call(this) }

); } } export default SelectBoxes;

In the constructor, we’ve initialized the state with an array containing the select state for each of the boxes. These boxes represent the files. The renderBoxes() method renders the boxes and styles them according to their select state. If a box is clicked without simultaneously pressing the Ctrl key, it resets the state to its default one (everything is deselected) because ctrlKey property would have false as its value. Below that, we simply toggle the select state of the box being clicked on.

Another example is keyboard events such as onKeyUp, onKeyDown and onKeyPress. When used, each of these events have properties pertaining to the actual key that you pressed:

  • altKey – a boolean value indicating whether the alt key is pressed along with another key.
  • charCode – the code of the key being pressed.
  • ctrlKey – a boolean value indicating whether the Ctrl key is pressed along with another key.
  • key – the actual key that was pressed.
  • shiftKey – a boolean value indicating whether the shift key is pressed along with another key.
  • which – pretty much the same as the charCode.

There are many other properties which you can use based on the event type, so be sure to check out the list of supported events in React.

React Event Handling Gotchas

Lastly, let’s take a look at some of the most common gotchas when it comes to event handling:

  • this can have different meaning.
  • You can’t listen to events directly from your custom components.
  • Not all DOM events have SyntheticEvent equivalents.

this can have different meaning

this can have a different meaning depending on how you attached the event handling function. For example, in the ShowAlert component earlier. We just specified the function directly without binding it to the component context:


This is because we didn’t really need to access anything in the component context (e.g. the state). But if you need to be able to access the state and manipulate it, you have to use bind to bind the component context to the function. This way you can use this inside the function to refer to the component itself:


Note that this is only true if you’re using ES6 classes to declare your components. If you’re using React.createClass, this will always refer to the component without the need to use bind.

You can’t listen to events directly from your custom components

If you have a custom component named Box, you can’t do something like this:

import Box from './components/Box';

class App extends Component {

  danceBox() {
    //make the box dance
  }

  render() {
    return 
  }
}

See what we did there? We added the onClick event handler directly to the Box component. But this wouldn’t really work because this only means we’re passing in an onClick props to the Box component. To actually attach the click event handler, you need to add onClick to the actual component. It’s not really a good practice to use reserved words for props so you need to change the name as well:

Then on the Box component, use the clickHandler props:

Not all DOM events have SyntheticEvent equivalents

If you compare the DOM events listed on MDN with the Synthetic events in React, you’ll see that not all of the DOM events has an equivalent synthetic event. For example, there’s no synthetic event for listening for when the browser window is resized. In such cases, we need to fallback to DOM events to do the work for us. All you have to do is to attach the event listener using window.addEventListener. This accepts the event you want to listen to as its first argument, and the function that will handle the event as the second argument. The attaching of the event listener is done when the component has been mounted (componentDidMount). Don’t forget to remove it when the component is unmounted (componentWillUnmount). The handleResizedScreen function handles the event by getting the current width and height of the window, then updating the state so that the displayed width and height also changes.

import React, { Component } from 'react';
import '../App.css';

class ResizeWindow extends Component {

  constructor(props) {
    super(props);
    this.state = {
        width: window.innerWidth,
        height: window.innerHeight
    };
  }

  handleResizedScreen() {
    this.setState({
        width: window.innerWidth,
        height: window.innerHeight
    });
  }

  componentDidMount() {
    window.addEventListener("resize", this.handleResizedScreen.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.handleResizedScreen.bind(this));
  }

  render() {
    return (

 

{ this.state.width } x { this.state.height }
); } } export default ResizeWindow;

Here are the contents of the App.css file:

.centered {
  position: fixed; 
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 30px;
}

Conclusion

That’s it! In this tutorial you’ve learned all about events in React. With this knowledge, you’ll now be able to create React apps that makes full use of events. You can find all the codes used in this tutorial in this Github repo. For more information regarding events in React, check out the official documentation on Events.

, ,

JavaScript Events 101

A lot of things happen on webpages. People scroll, click, and move their mouses. Form inputs get entered and typed into. Pages load or get resized. These actions (and many others) are aptly called ‘events’ in web development. And responding to these events is a large part of what makes web applications interactive. Users do things on a page and the page responds in turn. JavaScript is what we use to handle events and give an appropriate response to them.

This post will give a background and overview (with code examples) of how we can handle events with JavaScript. We’ll stay at a relatively high-level so you can quickly learn the gist of events without getting bogged down in minutiae.

Types of Events

Before covering the 3 primary ways of handling JavaScript events, it’s worth knowing what types of events there are. MDN has the one of the easiest to read resources on this. If you go there, you’ll see there’s a ton of different event types! WebMonkey has a nice categorization of them:

  • Page Events
  • Form Events
  • Keyboard Events
  • Mouse Events

I think those are mostly self-explanatory and can help you chunk the events better. You don’t need to know every event in the spec by heart. The big takeaway here is that we can track and respond to just about everything a user might do on a webpage. So what are the primary ways that we can do this? Read on.

Method #1: Event Handlers

Event handlers are the first way that developers respond(ed) to events. Event handlers are also called inline event handlers. That’s because they are put right into the html elements. You’ve probably seen them in the form on onclick or onload.

As you can see here, the onClick handler is put right onto the the anchor element. It will alert ‘welcome’ if it is clicked. Seems pretty straightforward, so what are the disadvantages of this approach?

Disadvantages:

  • Mixing markup with functionality

This breaks the separation of concerns tenet in programming. You generally want to keep JavaScript separate from HTML and not mix the two. This also applies to inline styling with CSS (inline styling is generally bad).

  • You can only put one handler per element

If you need to respond to other types of events on that element, too bad.

  • HTML file size

Putting event handlers in your HTML is going to make your pages a lot heavier.

  • Difficult code maintenance

If you need to make changes to your event handlers you’re going to have to do so on every single element vs. changing things once in a Javascript file.

  • Polluting Global Scope

This is a big No-No in JavaScript. You do not want to put unnecessary methods onto the global object because this could cause collisions if someone else uses the same method name for their code.

So event handlers were what came first and they work but there’s many drawbacks. Event listeners offer us a much better way to do this.

Method #2: Event Listeners (Observer pattern)

This event pattern relies on something called the “observer model”. The observer is the browser. The developer registers event listeners with the browser and says “hey browser, listen up. If this particular action happens, do this (aka run this function)”.

An Element, a Method, an Event, a Function…

The syntax for registering an event listener is pretty simple. Check out this jsfiddle that shows you which event is currently occurring on a page. Here’s an example from that fiddle.

Another way to understand this is imagine the developer is saying “Hey Browser, listen for when someone mouses over the document (the entire page). When they do that, call the sendOutput function. Note: you can register event listeners on any DOM nodes, not just HTML elements.

So event listeners are clearly an improvement over events handlers. So what are the downsides of using them?

  • Performance

Event listeners are not free. Your page/app will slow down when you have to attach Event Listeners to several hundred or thousand nodes.

  • Tedium

It takes a lot of extra work and maintenance to register and track so many event listeners in an HTML document. What if you have list items or particular DOM nodes that are coming and going and changing a lot? With event listeners, you’re going to have to be constantly attaching and removing listeners as the DOM changes.

Event listeners give us a much better syntax but they are also not without their drawbacks.

A note about Bubbling and Capturing

You now need to know a bit about the phases of events. This can be a bit of a rabbit hole so we’ll try to keep this simple and high-level.

An event does not just occur on the element itself. It also occurs on all of its ancestors (parents and grandparents and so on). Let me show you with a code demo or we’ll get lost here otherwise.

What’s happening there? The term is event propagation, which includes capturing and bubbling. Capturing starts at the highest level of the DOM and fires/propagates the event on every ancestor until it hits the exact element where the event occurs. It then does the reverse in a process called bubbling.

Capturing makes a sound like this:

Bubbling, however, sounds like this:

Capturing/Bubbling are a rabbit hole like I said. They have to do with Netscape vs. Microsoft in the 90s and compromises and the chaotic evolution of the technologies that make up our beloved Internet. But we don’t need to go there.

Instead, let’s just focus on bubbling. Bubbling is where an event on a child (e.g. <li>) will propagate up to it’s parents, their parents, and their parents, all the way to the root of the document. Bubbling is what allows us to do event delegation.

Method #3 – Event Delegation

We know events are going to bubble up the DOM. So imagine we have some HTML like this:

<html>

<body>

 <ul>

 <li id="li_1"><button id="button_1">Button A</button></li>

 <li id="li_2"><button id="button_2">Button B</button></li>

 <li id="li_3"><button id="button_3">Button C</button></li>

 </ul>

</body>

</html>

Now imagine that someone clicks on one of those buttons. If we were to use Method #2 (Event Listeners), we’d have to register a separate event listener onto each of those buttons (bleck).

But we know the event will bubble up from the <li> to the <ul> parent. What if we register an event listener on the <ul> and have it figure out which of its children got clicked? This is event delegation in a nutshell. The key is listen on the parents, not the children. Here’s the syntax.

Here’s the code in action. I’m going to use jQuery and explain why later.

jQuery excels at simplifying event delegation. You can, of course, do it in vanilla js but it takes roughly 4-5x as many lines.

In that particular example, I’m logging the event.target.nodeName. But try logging the event.target or just the event to get a sense for what other types of properties the event objects contain.

Here’s another really cool demo I found on CodePen where you can learn more about Bubbling through play:

See the Pen Bubbler – an event bubbling demonstration by Adam McFadden (@adammcfadden) on CodePen.


Summary

This article covered, at a high level, how events can be handled using JavaScript. There’s a lot more to the story then we could cover in 1300 words so below I’m going to put some recommended reading if you’d like to dig in more. That said this should give you enough of a conceptual framework for how events have evolved and how developers use JavaScript to respond to them.

Recommended Reading

Event Delegation – David Walsh Blog

Monitor all JavaScript events in the browser console

Emerging Patterns in JavaScript Event Handling