Using React's useEffect to implement a mousedown event listener

I created a modal that automatically closes when the user clicks outside of it.

method one - involves passing isModalOpened to update the state only if the modal is currently open.

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOutside = (e) => {
  if (!ref.current.contains(e.target) && isModalOpened) {
     toggleModal(false);
  }
};

React.useEffect(() => {
  window.addEventListener('mousedown', clickOutside);

  return () => {
     window.removeEventListener('mousedown', clickOutside);
  };
}, [isModalOpened]);

method two - excludes isModalOpened from the dependency array.

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOutside = (e) => {
  if (!ref.current.contains(e.target)) {
     toggleModal(false);
  }
};

React.useEffect(() => {
  window.addEventListener('mousedown', clickOutside);

  return () => {
     window.removeEventListener('mousedown', clickOutside);
  };
}, []);

Concern: Am I supposed to include isModalOpened in the dependency array or not?

Answer №1

There is no requirement for it.

This is because toggling the modal to the same false value does not trigger a re-render.

Therefore, there is no need to check the value of `isModalOpened` and consequently exclude the variable from your function, eliminating the dependency altogether.

Answer №2

Avoid passing the isModalOpen variable to the deep array as it will result in the effect removing and adding the listener unnecessarily.

Answer №3

One way to approach this situation is by running the hook every time the status of isModalOpened changes. This method involves removing the global listener when the modal closes. Another approach would be to trigger the hook when the component is either mounted or unmounted, ensuring that the global listener remains active throughout the lifecycle of the component.

The best choice between the two approaches depends on how you intend to utilize the component. If you plan to have the component mounted before opening the modal (thus starting with an initial state of false), the second option will constantly monitor the mousedown event from mounting until unmounting. However, if the component will only be mounted when the modal is open, it would be more appropriate to set the global listener only when the modal is indeed open.

In this scenario, the first approach is recommended.

*edit

It's worth noting that in your if statement, you can eliminate the need for checking the value of isModalOpened.

Answer №4

In my opinion, a slight adjustment could be made to improve the approach in this scenario. I would recommend wrapping the clickOut function within useCallback, where the dependencies include toggleModal and ref. Additionally, make clickOut a dependency in the useEffect. By doing this, whenever there is a change in either the ref or toggleModal, a new reference for clickOut will be created. Consequently, if there is a new reference for clickOut, listeners will be reassigned in the useEffect. This not only prevents unnecessary creation of the clickOut function on each render but also optimizes rendering.

Based on my suggestion, your code should appear as follows:

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOut = useCallback((e) => {
  if (!ref.current.contains(e.target) && isModalOpened) {
     toggleModal(false);
  }
}, [isModalOpened, ref]);

React.useEffect(() => {
  window.addEventListener('mousedown', clickOut);

  return () => {
     window.removeEventListener('mousedown', clickOut);
  };
}, [clickOut]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Dropdown menu of countries created with Material UI

I have been working on creating a dropdown menu in my form that lists all countries. I used an Array of strings with country names and mapped through it to generate the options for the select dropdown. However, the dropdown menu does not seem to be worki ...

When utilizing jQuery.Mockjax to simulate the JSON data, the Backbone.Collection.fetch() function consistently results in a 404 error

My setup is pretty straightforward: Main.js: (function($) { "use strict"; var Company = Backbone.Model.extend({ defaults: { title: "", description: "" }, initialize: function() { ...

I'm having trouble with getting npm start to function properly. I've exhausted all my options and I'm feeling lost

Every time I execute npm start in my React project, an error pops up: [email protected] start C:\Users\AyaLe\Desktop\React\myapp react-scripts start It seems there might be a problem with the project's dependency tre ...

Connecting a Database with NestJS and TypeORM: A step-by-step guide to establish a connection with TypeORM and ensure easy access to

Could someone please explain how to create a DB instance using TypeORM? I want it to be accessible like this service, but the Connection class is deprecated. import { Inject, Injectable } from '@nestjs/common'; import { Connection, Repository } ...

Exploring the world of WebSockets and Socket.io

Recently many online games, like , have started using WebSockets to create real-time MMORPGs. I'm curious about how to develop a node.js program that can manage connections from browsers using WebSockets. Here is an example of browser code: <!DOC ...

Retrieving JSON data value without a key using AngularJS

I am struggling to retrieve a data value from a JSON array in Angular that does not have a key value. While I have come across examples of extracting values with keys, I haven't been able to crack this particular piece. The JSON returned from the API ...

How can I troubleshoot the unresponsive remove div function on my website?

My code is running fine on CodePen (link provided below), but for some reason, it's not working properly in the web browser. I am executing the code from localhost and the button isn't responding as expected. CODE Here is my Visual Studio code ...

Error: Attempting to access the 'SearchBox' property of an undefined variable is not allowed

I have been working on a Google Maps code that displays both public and private schools with different markers for each category. However, when running the code, I encountered an error specifically on this line of code: var searchBox = new google.maps.pl ...

Utilizing form data binding with multiple instances of forms in React

Parent Component Within my parent component, named Users, there is a snippet of code that includes the functions for adding and updating users: addUser(index, user) { var users = this.state.users var existingUser = users[index] if (existingUse ...

Accessing CSV data stored externally using JavaScript

Hi there, I am struggling to load external CSV data into a script due to what I believe is the browser's same origin policy restriction. I came across some information about using cross-document messaging as a workaround, but I have no idea how to go ...

Using the mapState function in vuex allows for easy access to Vue methods

I have an important task to complete while the data is being computed using vuex mapState. I must ensure that the vue method countAlerts is called every time the data changes; however, the computed property needs to invoke this method and unfortunately, ...

Establishing a small boutique utilizing Vue.observable for property getters

I am currently importing the createStore function into a store.js file and passing an object with state properties and mutation functions as an argument, which is working well. createStore.js import Vue from 'vue' function createStore({ state, ...

Ways to eliminate the absence of the 'Access-Control-Allow-Origin' header in an error message when using a Java-based web-service server

I'm currently working on developing a webservice using Java as the server and Javascript as the client. My goal is to send a Post request with JSON data and receive a Post response with JSON data from the server. However, since the client and server h ...

a single button with dual functionalities

I am new to the development field and have a question about jQuery. I want a single button to perform two different actions. For example, let's say we have a button labeled Pause/Resume. When I click on the button, it should first display "Pause", and ...

Which JavaScript framework tackles the challenges of managing asynchronous flow, callbacks, and closures?

I have a strong aversion to JavaScript. I find it to be quite messy and disorganized as a language. However, I recognize that my lack of proficiency in coding with it may contribute to this perception. These past few days have been incredibly frustrating ...

Invoke the session on a different page and incorporate it into your JavaScript code

My php files, ajax.php and index.php, contain a mix of php code, html, and javascript. I am developing a quiz website where questions are retrieved from a database using sql in ajax.php and displayed on index.php through an ajax method. The user's sco ...

Can you explain the functionality behind the shouldForwardProp parameter in the styled() method?

I understand that the shouldForwardProp function determines which props should be passed to the wrapped element when using styled(). However, I am struggling to find a practical example of its usage. Is prop forwarding in this scenario similar to prop dri ...

Issue with React state not updating as per expectation, values in body are not being identified by backend system

I am currently facing a puzzling situation with a component in my React application. This component conditionally sets values based on state and button clicks, then sends the data object to RTK Query and ultimately to a controller in mongoose/express. Two ...

After successfully deploying on Netlify, ReactDOM.createRoot() does not insert the #root div

Currently experiencing an issue while attempting to deploy a React application on Netlify. The app functions correctly in the local environment, and the deployment process completes without errors. However, upon previewing the site, the <App> compone ...

Encountering special symbols in the ID of a form element triggers an error message in jQuery validator, stating 'Unrecognized expression'

One of the challenges I am facing is that I have a form with elements that have ids containing special symbols. For example: The id="$FormData[1]$PersonData[1]$PhysicalPerson[1]$PersonName[1]$Affix[@type='qualification' and @position='prefi ...