Tutorial

How To Handle DOM and Window Events with React

Published on August 28, 2020
How To Handle DOM and Window Events with React

The author selected Creative Commons to receive a donation as part of the Write for DOnations program.

Introduction

In web development, events represent actions that happen in the web browser. By responding to events with event handlers, you can create dynamic JavaScript applications that respond to any user action, including clicking with a mouse, scrolling along a webpage, touching a touch screen, and more.

In React apps, you can use event handlers to update state data, trigger prop changes, or prevent default browser actions. To do this, React uses a SyntheticEvent wrapper instead of the native Event interface. SyntheticEvent closely emulates the standard browser event, but provides more consistent behavior for different web browsers. React also gives you tools to safely add and remove a Window event listener when a component mounts and unmounts from the Document Object Model (DOM), giving you control over Window events while preventing memory leaks from improperly removed listeners.

In this tutorial, you’ll learn how to handle events in React. You’ll build several sample components that handle user events, including a self-validating input component and an informative tooltip for the input form. Throughout the tutorial, you’ll learn how to add event handlers to components, pull information from the SyntheticEvent, and add and remove Window event listeners. By the end of this tutorial, you’ll be able to work with a variety of event handlers and apply the catalog of events supported by React.

Prerequisites

Step 1 — Extracting Event Data with SyntheticEvent

In this step, you’ll create a validating component using an <input> HTML element and the onChange event handler. This component will accept input and validate it, or make sure that the content adheres to a specific text pattern. You’ll use the SyntheticEvent wrapper to pass event data into the callback function and update the component using the data from the <input>. You will also call functions from the SyntheticEvent, such as preventDefault to prevent standard browser actions.

In React, you don’t need to select elements before adding event listeners. Instead, you add event handlers directly to your JSX using props. There are a large number of supported events in React, including common events such as onClick or onChange and less common events such as onWheel.

Unlike native DOM onevent handlers, React passes a special wrapper called SyntheticEvent to the event handler rather than the native browser Event. The abstraction helps reduce cross-browser inconsistencies and gives your components a standard interface for working with events. The API for SyntheticEvent is similar to the native Event, so most tasks are accomplished in the same manner.

To demonstrate this, you will start by making your validating input. First, you will create a component called FileNamer. This will be a <form> element with an input for naming a file. As you fill in the input, you’ll see the information update a preview box above the component. The component will also include a submit button to run the validation, but for this example the form will not actually submit anything.

First, create the directory:

  1. mkdir src/components/FileNamer

Then open FileNamer.js in your text editor:

  1. nano src/components/FileNamer/FileNamer.js

Inside FileNamer.js, create a wrapper <div>, then add another <div> with a class name of preview and a <form> element inside the wrapper by writing the following lines of code:

events-tutorial/src/components/FileNamer/FileNamer.js
import React from 'react';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
      </div>
      <form>
      </form>
    </div>
  )
}

Next, add an input element for the name to display in the preview box and a Save button. Add the following highlighted lines:

events-tutorial/src/components/FileNamer/FileNamer.js
import React from 'react';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview:</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

In the preview <div>, you added an <h2> element with the text Preview. This will be your preview box. Inside your form, you added an <input> surrounded by a <label> element with Name: as its text. Then you added a button called Save directly before the closing <form> tag.

Save and close the file.

Next, open App.js:

  1. nano src/components/App/App.js

Import FileNamer, then render inside the App function by adding the following highlighted lines:

events-tutorial/src/components/App/App.js
import React from 'react';
import FileNamer from '../FileNamer/FileNamer';

function App() {
    return <FileNamer />
}

export default App;

Save and close the file. When you do the browser will refresh and you’ll see your component.

Name element

Next, add some light styling to help define the sections and to add some padding and margins to the elements.

Open FileNamer.css in your text editor:

  1. nano src/components/FileNamer/FileNamer.css

Give the .preview class a gray border and padding, then give the .wrapper class a small amount of padding. Display the items in a column using flex and flex-direction, and make all the text align left. Finally, remove the default button styles by removing the border and adding a black border:

events-tutorial/src/components/FileNamer/FileNamer.css
.preview {
    border: 1px darkgray solid;
    padding: 10px;
}

.wrapper {
    display: flex;
    flex-direction: column;
    padding: 20px;
    text-align: left;
}

.wrapper button {
    background: none;
    border: 1px black solid;
    margin-top: 10px;
}

Save and close the file. Then open FileNamer.js:

  1. nano src/components/FileNamer/FileNamer.js

Import the styles to apply them to your component:

events-tutorial/src/components/FileNamer/FileNamer.js
import React from 'react';
import './FileNamer.css';

export default function FileNamer() {
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview:</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

Save the file. When you do, the browser will refresh and you’ll find the component has the new styles.

Styled component

Now that you have a basic component, you can add event handlers to the <input> element. But first, you’ll need a place to store the data in the input field. Add the useState Hook to hold the input:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

In this code, you destructured useState into a variable name to hold the input and a function called setName to update the data. Then you displayed the name in the preview section followed by the .js extension, as if the user were naming a file.

Now that you can store the input data, you can add an event handler to the <input> component. There are often several different event handlers you can use for a given task. In this case, your app needs to capture the data the user types into the element. The most common handler for this situation is onChange, which fires every time the component changes. However, you could also use keyboard events, such as onKeyDown, onKeyPress, and onKeyUp. The difference primarily has to do with when the event fires and the information passed to the SyntheticEvent object. For example, onBlur, an event for when an element becomes unfocused, fires before onClick. If you want to handle user information before another event fires, you can pick an earlier event.

Your choice of event is also determined by the type of data you want to pass to the SyntheticEvent. The onKeyPress event, for example, will include the charCode of the key that the user pressed, while onChange will not include the specific character code, but will include the full input. This is important if you want to perform different actions depending on which key the user pressed.

For this tutorial, use onChange to capture the entire input value and not just the most recent key. This will save you the effort of storing and concatenating the value on every change.

Create a function that takes the event as an argument and pass it to the <input> element using the onChange prop:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input name="name" onChange={event => {}}/>
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

As mentioned earlier, the event here is not the native browser event. It’s the SyntheticEvent provided by React, which is often treated the same. In the rare case you need the native event, you can use the nativeEvent attribute on the SyntheticEvent.

Now that you have the event, pull out the current value from the target.value property of the event. Pass the value to setName to update the preview:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
           autoComplete="off"
           name="name"
           onChange={event => setName(event.target.value) }
         />
        </label>
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

In addition, you set the attribute autoComplete to "off" to turn off browser suggestions.

Save the file. When you do, the page will reload, and when you type in the <input> you’ll see an update in the preview.

Typing into the input element

Note: You could also access the name of the input using event.target.name. This would be useful if you were using the same event handler across multiple inputs, since the name would automatically match the name attribute of the component.

At this point, you have a working event handler. You are taking the user information, saving it to state, and updating another component with the data. But in addition to pulling information from an event, there are situations where you’ll need to halt an event, such as if you wanted to prevent a form submission or prevent a keypress action.

To stop an event, call the preventDefault action on the event. This will stop the browser from performing the default behavior.

In the case of the FileNamer component, there are certain characters that could break the process of choosing a file that your app should forbid. For example, you wouldn’t want a user to add a * to a filename since it conflicts with the wildcard character, which could be interpreted to refer to a different set of files. Before a user can submit the form, you’ll want to check to make sure there are no invalid characters. If there is an invalid character, you’ll stop the browser from submitting the form and display a message for the user.

First, create a Hook that will generate an alert boolean and a setAlert function. Then add a <div> to display the message if alert is true:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autoComplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert && <div> Forbidden Character: *</div>}
        <div>
          <button>Save</button>
        </div>
      </form>
    </div>
  )
}

In this code, you used the && operator to only show the new <div> if alert is set equal to true first. The message in the <div> will tell the user that the * character is not allowed in the input.

Next, create a function called validate. Use the regular expression .test method to find out if the string contains a *. If it does, you will prevent the form submission:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);
  const validate = event => {
    if(/\*/.test(name)) {
      event.preventDefault();
      setAlert(true);
      return;
    }
      setAlert(false);
 };

  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autoComplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert && <div> Forbidden Character: *</div>}
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

When the validate function is called and the test returns true, it will use event.preventDefault then call setAlert(true). Otherwise, it will call setAlert(false). In the last part of the code, you added the event handler to the <button> element with onClick.

Save the file. As before, you could have also used onMouseDown, but onClick is more common and thus allows you to avoid any unexpected side effects. This form doesn’t have any submit actions, but by preventing the default action, you prevent the page from reloading:

Prevent Default and trigger a warning

Now you have a form that uses two event handlers: onChange and onClick. You are using the event handlers to connect user actions to the component and the application, making it interactive. In doing so, you learned to add events to DOM elements, and how there are several events that fire on the same action, but that provide different information in the SyntheticEvent. You also learned how to extract information from the SyntheticEvent, update other components by saving that data to state, and halt an event using preventDefault.

In the next step, you’ll add multiple events to a single DOM element to handle a variety of user actions.

Step 2 — Adding Multiple Event Handlers to the Same Element

There are situations when a single component will fire multiple events, and you’ll need to be able to connect to the different events on a single component. For example, in this step you’ll use the onFocus and onBlur event handlers to give the user just-in-time information about the component. By the end of this step, you’ll know more about the different supported events in React and how to add them to your components.

The validate function is helpful for preventing your form from submitting bad data, but it’s not very helpful for user experience: The user only receives information about the valid characters after they’ve filled out the entire form. If there were multiple fields, it wouldn’t give the user any feedback until the last step. To make this component more user friendly, display the allowed and disallowed characters when the user enters the field by adding an onFocus event handler.

First, update the alert <div> to include information about what characters are allowed. Tell the user alphanumeric characters are allowed and the * is not allowed:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        {alert &&
         <div>
           <span role="img" aria-label="allowed"></span> Alphanumeric Characters
           <br />
           <span role="img" aria-label="not allowed">⛔️</span> *
         </div>
       }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

In this code, you used Accessible Rich Internet Applications (ARIA) standards to make the component more accessible to screen readers.

Next, add another event handler to the <input> element. You will alert the user about the allowed and disallowed characters when they activate the component by either clicking or tabbing into the input. Add in the following highlighted line:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
            onFocus={() => setAlert(true)}
          />
        </label>
        {alert &&
          <div>
            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
            <br />
            <span role="img" aria-label="not allowed">⛔️</span> *
          </div>
        }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

You added the onFocus event handler to the <input> element. This event triggers when the user selects the field. After adding the event handler, you passed an anonymous function to onFocus that will call setAlert(true) and display the data. In this case, you don’t need any information from the SyntheticEvent; you only need to trigger an event when the user acts. React is still sending the SyntheticEvent to the function, but in the current situation you don’t need to use the information in it.

Note: You could trigger the data display with onClick or even onMouseDown, but that wouldn’t be accessible for users that use the keyboard to tab into the form fields. In this case, the onFocus event will handle both cases.

Save the file. When you do, the browser will refresh and the information will remain hidden until the user clicks on the input.

Trigger the event when clicking on the input

The user information now appears when the field is focused, but now the data is present for the duration of the component. There’s no way to make it go away. Fortunately, there’s another event called onBlur that fires when the user leaves an input. Add the onBlur event handler with an anonymous function that will set the alert to false. Like onFocus, this will work both when a user clicks away or when a user tabs away:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onBlur={() => setAlert(false)}
            onChange={event => setName(event.target.value) }
            onFocus={() => setAlert(true)}
          />
        </label>
        {alert &&
          <div>
            <span role="img" aria-label="allowed"></span> Alphanumeric Characters
            <br />
            <span role="img" aria-label="not allowed">⛔️</span> *
          </div>
        }
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

Save the file. When you do, the browser will refresh and the information will display when the user clicks on the element and disappear when the user clicks away:

Show information on focus and hide on blur

You can add as many event handlers as you need to an element. If you have an idea of an event you need, but aren’t sure of the name, scroll through the supported events and you may find what you need.

In this step you added multiple event handlers to a single DOM element. You learned how different event handlers can handle a broad range of events—such as both click and tab—or a narrow range of events.

In the next step, you’ll add global event listeners to the Window object to capture events that occur outside the immediate component.

Step 3 — Adding Window Events

In this step, you’ll put the user information in a pop-up component that will activate when the user focuses an input and will close when the user clicks anywhere else on the page. To achieve this effect, you’ll add a global event listener to the Window object using the useEffect Hook. You’ll also remove the event listener when the component unmounts to prevent memory leaks, when your app take up more memory than it needs to.

By the end of this step, you’ll be able to safely add and remove event listeners on individual components. You’ll also learn how to use the useEffect Hook to perform actions when a component mounts and unmounts.

In most cases, you’ll add event handlers directly to DOM elements in your JSX. This keeps your code focused and prevents confusing situations where a component is controlling another component’s behavior through the Window object. But there are times in which you’ll need to add global event listeners. For example, you may want a scroll listener to load new content, or you may want to capture click events outside of a component.

In this tutorial, you only want to show the user the information about the input if they specifically ask for it. After you display the information, you’ll want to hide it whenever the user clicks the page outside the component.

To start, move the alert display into a new <div> with a className of information-wrapper. Then add a new button with a className of information and an onClick event that will call setAlert(true):

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
...
  return(
    <div className="wrapper">
      <div className="preview">
        <h2>Preview: {name}.js</h2>
      </div>
      <form>
        <label>
          <p>Name:</p>
          <input
            autocomplete="off"
            name="name"
            onChange={event => setName(event.target.value) }
          />
        </label>
        <div className="information-wrapper">
          <button
            className="information"
            onClick={() => setAlert(true)}
            type="button"
          >
            more information
          </button>
         {alert &&
           <div className="popup">
             <span role="img" aria-label="allowed"></span> Alphanumeric Characters
             <br />
             <span role="img" aria-label="not allowed">⛔️</span> *
           </div>
         }
        </div>
        <div>
          <button onClick={validate}>Save</button>
        </div>
      </form>
    </div>
  )
}

You also removed the onFocus and onBlur handlers from the <input> element to remove the behavior from the last step.

Save and close the file. Then open FileNamer.css:

  1. nano src/components/FileNamer/FileNamer.css

Add some styling to absolutely position the popup information above the button. Then change the <button> with a class of information to be blue with no border.

events-tutorial/src/components/FileNamer/FileNamer.css

.information {
   font-size: .75em;
   color: blue;
   cursor: pointer;
}

.wrapper button.information {
    border: none;
}

.information-wrapper {
   position: relative;
}

.popup {
    position: absolute;
    background: white;
    border: 1px darkgray solid;
    padding: 10px;
    top: -70px;
    left: 0;
}

.preview {
    border: 1px darkgray solid;
    padding: 10px;
}

.wrapper {
    display: flex;
    flex-direction: column;
    padding: 20px;
    text-align: left;
}

.wrapper button {
    background: none;
    border: 1px black solid;
    margin-top: 10px;
}

Save and close the file. When you do, the browser will reload, and when you click on more information, the information about the component will appear:

Trigger information pop-up

Now you can trigger the pop-up, but there’s no way to clear it. To fix that problem, add a global event listener that calls setAlert(false) on any click outside of the pop-up.

The event listener would look something like this:

window.addEventListener('click', () => setAlert(false))

However, you have to be mindful about when you set the event listener in your code. You can’t, for example, add an event listener at the top of your component code, because then every time something changed, the component would re-render and add a new event listener. Since your component will likely re-render many times, that would create a lot of unused event listeners that take up memory.

To solve this, React has a special Hook called useEffect that will run only when specific properties change. The basic structure is this:

useEffect(() => {
 // run code when anything in the array changes
}, [someProp, someOtherProp])

In the simplified example, React will run the code in the anonymous function whenever someProp or someOtherProp changes. The items in the array are called dependencies. This Hook listens for changes to the dependencies and then runs the function after the change.

Now you have the tools to add and remove a global event listener safely by using useEffect to add the event listener whenever alert is true and remove it whenever alert is false.

There is one more step. When the component unmounts, it will run any function that you return from inside of your useEffect Hook. Because of this, you’ll also need to return a function that removes the event listener when the component unmounts.

The basic structure would be like this:

useEffect(() => {
 // run code when anything in the array changes
  return () => {} // run code when the component unmounts
}, [someProp, someOtherProp])

Now that you know the shape of your useEffect Hook, use it in your application. Open up FileNamer.js:

  1. nano src/components/FileNamer/FileNamer.js

Inside, import useEffect, then add an empty anonymous function with a dependency of alert and setAlert in the array after the function:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
  }, [alert, setAlert]);
...

In this code, you added both alert and setAlert. To be complete, React recommends you add all external dependencies to the useEffect function. Since you will be calling the setAlert function, it can be considered a dependency. setAlert will not change after the first render, but it’s a good practice to include anything that could be considered a dependency.

Next, inside the anonymous function, create a new function called handleWindowClick that calls setAlert(false):

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
  }, [alert, setAlert]);
  ...
}

Then add a conditional that will call window.addEventListener('click', handleWindowClick) when alert is true and will call window.removeEventListener('click', handleWindowClick) when alert is false. This will add the event listener every time you trigger the pop-up and remove it everytime the pop-up is closed:

events-tutorial/src/components/FileNamer/FileNamer.js
import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
    if(alert) {
      window.addEventListener('click', handleWindowClick);
    } else {
      window.removeEventListener('click', handleWindowClick);
    }
  }, [alert, setAlert]);
  ...
}

Finally, return a function that will remove the event listener. Once again, this will run when the component unmounts. There may not be a live event listener, but it’s still worth cleaning up in situations where the listener still exists:

events-tutorial/src/components/FileNamer/FileNamer.js

import React, { useEffect, useState } from 'react';
import './FileNamer.css';

export default function FileNamer() {
  const [name, setName] = useState('');
  const [alert, setAlert] = useState(false);

  useEffect(() => {
    const handleWindowClick = () => setAlert(false)
    if(alert) {
      window.addEventListener('click', handleWindowClick);
    } else {
      window.removeEventListener('click', handleWindowClick)
    }
    return () => window.removeEventListener('click', handleWindowClick);
  }, [alert, setAlert]);
  ...
}

Save the file. When you do, the browser will refresh. If you click on the more information button, the message will appear. If you look at the global event listeners in the developer tools, you’ll see there is a click listener:

Click event listener

Click anywhere outside the component. The message will disappear and you’ll no longer see the global click event listener.

No click event listener

Your useEffect Hook successfully added and removed a global event listener based on a user interaction. It wasn’t tied to a specific DOM element, but was instead triggered by a change in the component state.

Note: From an accessibility standpoint, this component is not complete. If a user is not able to use the mouse, they will be stuck with an open pop-up because they would never be able to click outside the component. The solution would be to add another event listener for keydown that would also remove the message. The code would be nearly identical except the method would be keydown instead of click.

In this step you added global event listeners inside a component. You also learned how to use the useEffect Hook to properly add and remove the event listener as the state changes and how to clean up event listeners when the component unmounts.

Conclusion

Event handlers give you the opportunity to align your components with user actions. These will give your applications a rich experience and will increase the interactive possibilities of your app. They will also give you the ability to capture and respond to user actions.

React’s event handlers let you keep your event callbacks integrated with the HTML so that you can share functionality and design across an application. In most cases, you should focus on adding event handlers directly to DOM elements, but in situations where you need to capture events outside of the component, you can add event listeners and clean them up when they are no longer in use to prevent memory leaks and create performative applications.

If you would like to look at more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page. To learn more about events in JavaScript, read our Understanding Events in JavaScript and Using Event Emitters in Node.js tutorials.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products


Tutorial Series: How To Code in React.js

React is a popular JavaScript framework for creating front-end applications, such as user interfaces that allow users to interact with programs. Originally created by Facebook, it has gained popularity by allowing developers to create fast applications using an intuitive programming paradigm that ties JavaScript with an HTML-like syntax known as JSX.

In this series, you will build out examples of React projects to gain an understanding of this framework, giving you the knowledge you need to pursue front-end web development or start out on your way to full stack development.

About the authors

Default avatar

Senior Technical Editor

Editor at DigitalOcean, fiction writer and podcaster elsewhere, always searching for the next good nautical pun!


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
3 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

This tutorial is broken at the last step. Clicking on the “more information” button doesn’t show the alert div.

I think clicking on the “more information” button bubbles up and triggers the window’s click event. So, it immediately does setAlert(false).

I worked around the problem with some changes to the “more information” button’s onClick handler:

<button
  type="button"
  className="information"
  onClick={(event) => {
    setAlert(!alert);
    // preventDefault isn't necessary with type="button"
    event.preventDefault();
    event.stopPropagation();
  }}
>
  more information
</button>

I’m not sure how this happens. I know the post is a couple of years old. I don’t think the way browsers handle event bubbling has changed fundamentally in that time, but the author has animated GIFs showing that it works ::shrug::

Hi @joemorgan, thank you for a fantastic tutorials! I’m a bit stuck and I was wondering if you could possibly give me a bit of advice! When adding the useEffect hook the pop up only flashes up before disappearing when clicking “more information” or typing “*”. I’ve tried to debug my code - comparing and copy and pasting just to make sure but I still get the same outcome. Is there something I could have missed?

useEffect(() => {
    const handleWindowClick = () => setAlert(false)
    if(alert) {
      window.addEventListener('click', handleWindowClick);
    } 
    return () => window.removeEventListener('click', handleWindowClick);
  }, [alert, setAlert]);

Hi @joemorgan, I bet the else is redundant (at least it was confusing tom me) since React would unsubscribe from the listener not only when the component unmounts, but also before re-running the effect due to a subsequent render. Did I get it right?

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.