The big class to the p elements when the button is clicked.
We use the document.querySelectorAll() method to select all DOM elements to which we want to add the class.
We loop through the elements in the list object with its forEach() method. This forEach() method works much like ArrayforEach().
document.getElementsByClassName() method
We can use the document.getElementsByClassName() method in place of document.querySelectorAll() when the selector is a class selector. For getElementsByClassName(), we pass the class name without the . (dot), and we use Array.from() to convert the result to an array before the iteration with forEach().
JavaScriptCopied!
const elements = Array.from(document.getElementsByClassName('text'));
elements.forEach((element) => {
element.classList.add('big');
});
Note: Unlike the querySelectorAll() method, getElementByClassName() returns a live list of HTML Elements; changes in the DOM will reflect in the array as the changes occur. If an element in the array no longer qualifies for the selector specified in getElementsByClassName(), it will be removed automatically. This means that one iteration of the list could be different from another, even without any direct modifications to the list.
classList.add() method
We use the classList.add() method to add a class to each of the elements.
You can add multiple classes by passing more arguments to add().
JavaScriptCopied!
const elements = document.querySelectorAll('.text');
elements.forEach((element) => {
element.classList.add('big', 'blue');
});
If any of the classes passed to add() already exists on the element, add() will ignore this, instead of throwing an error.
Add class to elements with different selectors
Sometimes there is no common selector between the elements that you want to add the class to. For such a case, you can pass multiple comma-separated selectors to the querySelectorAll() method.
In this article, we’ll learn multiple ways to easily simulate a mouse click or tap on an element in the HTML DOM, using JavaScript.
Use click() method
This is the easiest and most basic method to simulate a mouse click on an element. Every HTMLElement has a click() method that can be used to simulate clicks on it. It fires the click event on the element when it is called. The click event bubbles up to elements higher in the document tree and fires their click events.
To use the click() method, you first need to select the element in JavaScript, using a method like querySelector() or getElementById(). You’ll be able to access the HTMLElement object from the method’s return value, and call the click() method on it to simulate the click.
Let’s see an example, where we simulate a button click every second, by calling click() in setInterval().
The button is clicked programmatically every 1 second.
Notice how there are no visual indicators of a click occurring because it’s a programmatic click.
Since click() causes the click event to fire on the element, any click event listeners you attach to the element will be invoked from a click() call.
In the following example, we use a click event listener (instead of setInterval) to increase the click count, and another listener to toggle the button’s style when clicked.
Alternatively, we can use a custom MouseEvent object to simulate a mouse click in JavaScript.
JavaScriptCopied!
const targetButton = document.getElementById('target');
const clickEvent = new MouseEvent('click');
targetButton.dispatchEvent(clickEvent);
The MouseEvent interface represents events that occur from the user interacting with a pointing device like the mouse. It can represent common events like click, dblclick, mouseup, and mousedown.
After selecting the HTMLElement and creating a MouseEvent, we call the dispatchEvent() method on the element to fire the event on the element.
The dispatched MouseEvent is passed to click listeners.
Apart from the event type passed as the first argument, we can pass options to the MouseEvent() constructor to control specific details about the event:
The elementFromPoint() method returns the topmost element at the specified coordinates, relative to the browser’s viewport. It returns an HTMLElement, which we call click() on to simulate the mouse click from JavaScript.
In the following example, we have a button and a containing div:
The #target button is at point (0, 0) in its #container, so point (200, 100) in the viewport.
To get the position of the #target with more certainty, we add an offset of 10px each to get the final position to search for: (210, 110).
JavaScriptCopied!
let clickCount = 0;
const clickCountEl = document.getElementById('click-count');
clickCountEl.innerText = clickCount;
const targetButton = document.getElementById('target');
targetButton.addEventListener('click', () => {
clickCount++;
clickCountEl.innerText = clickCount;
});
// Offset of 10px to get button's position in container
const x = 200 + 10;
const y = 100 + 10;
setInterval(() => {
const buttonAtPoint = document.elementFromPoint(x, y);
buttonAtPoint.click();
}, 1000);
To verify that we’re actually selected the button by its position and it’s getting clicks, we select it by its ID (target) and set a click event listener on the HTMLElement returned, which will increase the count of how many times it has been clicked.
And we’re successful:
A click is simulated on the button at point (210, 110).
Simulate mouse click at position with MouseEvent object
We can also simulate a mouse click on an element at a certain (x, y) position using a MouseEvent object and the dispatchEvent() method.
Here’s how:
JavaScriptCopied!
const clickEvent = new MouseEvent('click', {
view: window,
screenX: x,
screenY: y,
});
const elementAtPoint = document.elementFromPoint(x, y);
elementAtPoint.dispatchEvent(clickEvent);
This time we specify the screenX and screenY options when creating the MouseEvent.
screenX sets the position where the click event should occur on the x-axis. It sets the value of the MouseEvent‘s screenX property.
screenY sets the position where the click event should occur on the Y-axis. It sets the value of the MouseEvent‘s screenY property.
So we can use MouseEvent to replace the click() method in our last example:
JavaScriptCopied!
// ...
// Offset of 10px to get button's position in container
const x = 200 + 10;
const y = 100 + 10;
setInterval(() => {
const buttonAtPoint = document.elementFromPoint(x, y);
const clickEvent = new MouseEvent('click', {
view: window,
screenX: x,
screenY: y,
});
buttonAtPoint.dispatchEvent(clickEvent);
}, 1000);
Note:screenX and screenY doesn’t decide where the click should occur (elementFromPoint does). These options are set so that they can be accessed from any click event listener attached to the element at the point.
The “Unknown file extension .ts” error occurs in ts-node occurs when "type": "module" is set in your package.json file. To fix it, run the TypeScript file with ts-node --esm my-file.ts, or remove "type": "module" from your package.json file.
For example, in a project with this package.json file:
After doing this, you’ll be able to run the TypeScript file with only ts-node:
ShellCopied!
ts-node my-file.ts
Running the TypeScript file with only ts-node.
You may also need to add one or more of the following options to your tsconfig.json file:
tsconfig.jsonCopied!
{
// other settings..
"compilerOptions": {
// other compiler options...
"esModuleInterop": true,
"module": "ESNext", // "module": "CommonJS" should work too
"moduleResolution": "Node"
},
"include": ["/**/*.ts"],
"exclude": ["node_modules"]
}
Remove "type": "module" from tsconfig.json file
Alternatively, instead of doing all of the above, you can simply remove the "type": "module" field from your package.json file to fix the ERR_UNKNOWN_FILE_EXTENSION error in ts-node.
And you’ll be able to run the TypeScript file with ts-node successfully.
Compile TypeScript files into JavaScript
Another way to avoid ERR_UNKNOWN_FILE_EXTENSION is to stop using ts-node altogether. Instead, you can compile your TypeScript files with tsc and run the JavaScript output with node – the classic way.
ShellCopied!
# Compile with tsc
npx tsc --outDir dist my-file.ts
# Run with node
node dist/my-file.ts
Basic TypeScript compilation setup
Here’s a great way to set up your project for easily compiling and debugging TypeScript files.
First, install the TypeScript compiler:
ShellCopied!
npm i tsc
Then specify the src dir and out dir in tsconfig.json, and enable source maps for seamless Typescript debugging:
tsconfig.jsonCopied!
{
"compilerOptions": {
// ... other options
"rootDir": "src", // Location of TypeScript files
"outDir": "dist", // Location of compiled JavaScript files
"sourceMap": true // Generate sourcemaps
}
}
Finally, create a start NPM script that automatically runs the tsc and node commands one after the other:
You can easily get an object’s value by a key in Typescript using bracket notation, i.e., obj['key'], obj[myVar], etc. If the key exists, you will get the corresponding value back.
For example:
TypeScriptCopied!
type Car = {
name: string;
maxSpeed: number;
color: string;
};
const car: Car = {
name: 'CB Flash',
maxSpeed: 200,
color: 'blue',
};
console.log(car['name']); // CB Flash
// Dot notation
console.log(car.name); // CB Flash
// Get value by variable key
const prop = 'name';
console.log(car[prop]); // CB Flash
// Computed property key
const val = car[3 > 1 ? 'name' : 'maxSpeed']
console.log(val) // CB Flash
Dot notation property access
There are two ways to get an object’s value by a property key in TypeScript: dot notation and bracket notation.
In dot notation, we access an object value with the obj.propKey syntax.
TypeScriptCopied!
type Car = {
name: string;
maxSpeed: number;
color: string;
};
const car = {
name: 'CB Flash',
maxSpeed: 200,
color: 'blue',
};
console.log(car.name); // CB Flash
console.log(car.maxSpeed); // 200
console.log(car.color); // blue
With the obj.propKey syntax, the propKey must be a valid TypeScript identifier. Otherwise, a syntax error will be thrown:
TypeScriptCopied!
type Car = { [propKey: string]: string };
const car: Car = {};
car.100 = 'go faster'; // ❌ SyntaxError
console.log(car.100); // ❌ SyntaxError
propKey can also be a reserved keyword, like let, var, async, etc.
TypeScriptCopied!
type Car = { [propKey: string]: string };
const car: Car = {};
car.let = 'works';
car.await = 'works too';
console.log(car.let); // works
console.log(car.await); // works too
Bracket notation property access
In bracket notation, we access the property value with the obj[expression] syntax. The expression should evaluate to a string or Symbol that represent the property’s key.
TypeScriptCopied!
type Car = {
name: string;
maxSpeed: number;
color: string;
};
const car: Car = {
name: 'CB Flash',
maxSpeed: 200,
color: 'blue',
};
console.log(car['name']); // CB Flash
console.log(car['maxSpeed']); // 200
console.log(car['color']); // blue
Unlike dot notation, with bracket notation, we can access keys that are not valid TypeScript identifiers, like numbers and keys containing spaces.
TypeScriptCopied!
type Car = { [propKey: string]: string };
const car: Car = {};
car['100'] = 'go faster';
car['year produced'] = 2022;
console.log(car['100']); // go faster
console.log(car['year produced']); // 2022
Computed property names
The expression we put in-between the brackets can be as complex as possible, as long it evaluates to a string or Symbol.
For example, we can put a ternary expression in-between the brackets:
TypeScriptCopied!
type Car = {
name: string;
maxSpeed: number;
color: string;
};
const car: Car = {
name: 'CB Flash',
maxSpeed: 200,
color: 'blue',
};
const num = 3;
const val = car[num > 1 ? 'name' : 'maxSpeed'];
console.log(val); // CB Flash
Note: If the expression to the left of the ? is truthy, the ternary operator returns the value to the left. Otherwise, it returns the value to the right.
The ternary expression evaluates to the 'name' key, so the corresponding property value is returned.
To get the current year in Vue.js, create a new Date object with the Date() constructor, then use the getFullYear() method to get the year of the Date. getFullYear() will return a number that represents the current year.
We use the Date() constructor to create a new Date object. When Date() is called with no arguments, the Date object is created using the current date and time.
The DategetFullYear() method returns a number that represents the year of the Date. Since the Date object here stores the current date, getFullYear() returns the current year.
Get current year with data property
We can also put the current year in a data variable instead of placing it directly in the template with the {{ }} symbols. This allows us to more easily reuse the value in multiple places in the template markup.
While you could get each component of the date using different functions, a much more flexible and easy way to do this is by formatting the date in the given format with a format specifier.
We can carry out this formatting with the format() function from the date-fns library.
In the following example, we use date-fnsformat() to get the multiple individual parts of the date.
App.vueCopied!
<template>
<div>{{ dateString }}</div>
</template>
<script>
import { format } from 'date-fns';
export default {
data() {
return {
dateString: format(
new Date(),
"EEEE, 'the' do 'of' LLLL, yyyy"
),
};
},
computed() {
return {};
},
};
</script>
Different parts of the date are displayed using formatting.
The format() function takes a pattern and returns a formatted date string in the format specified by the pattern. You can find a list of the patterns format() accepts here.
For our example, we use the following patterns:
EEEE: to get the full name of the day of the week.
do: to get the ordinal day of the month, i.e., 1st, 2nd, 3rd, etc.
LLLL: to get the full name of the month of the year.
yyyy: to get the full year.
We also use single quotes to escape strings (the and of) that are not patterns but should be included in the result of the formatting.
The useEffect hook is called in a component after the first render and every time the component updates. By the timer useEffect is called, the real DOM would have been updated to reflect any state changes in the component.
Let’s take a look at a quick example to practically observe this behavior:
The first time the component renders from page loading, useEffect is called and uses the document.title property to set the page title to a string whose value depends on a count state variable.
The page title is changed from useEffect being called after the component is rendered.
If you watch closely, you’ll see that the page title was initially “Coding Beauty React Tutorial”, before the component was added to the DOM and the page title was changed from the useEffect call.
useEffect will also be called when the state is changed:
The page title is changed from useEffect being called after the component is updated.
As you might know, useEffect accepts an optional dependency array as its second argument. This array contains the state variables, props, and functions that it should watch for changes.
In our example, the dependency array contains only the count state variable, so useEffect will only be called when the count state changes.
useEffect called twice in React 18?
React 18 introduced a new development-only check to Strict Mode. This new check automatically unmounts and remounts a component when it mounts for the first time, and restores the previous state on the second mount.
Note: The check was added because of a new feature that will be added to React in the future. Learn more about it here.
This means that the first render causes useEffect to actually be called two times, instead of just once.
Here’s an example that lets us observe this new behavior.
It’s a basic time-counting app that implements the core logic that can be used to build timer and stopwatch apps.
We create an interval listener with setInterval() that increments a time state by 1 every second. The listener is in a useEffect that has an empty dependency array ([]), because we want it to be registered only when the component mounts.
But watch what happens when we check out the result on the web page:
The seconds go up by 2 every second.
The seconds are going up by 2 every second instead of 1! Because React 18’s new check causes the component to be mounted twice, an useEffect is called accordingly.
We can fix this issue by unregistering the interval listener in the useEffect‘s cleanup function.
The cleanup function that the useEffect callback returns is called when the component is mounted. So when React 18 does the compulsory first unmounting, the first interval listener is unregistered with clearInterval(). When the second interval listener is registered on the second mount, it will be the only active listener, ensuring that the time state is incremented by the correct value of 1 every second.
The seconds go up by 1 every second – success.
Note that even if we didn’t have this issue of useEffect being called twice, we would still have to unregister the listener in the cleanup function, to prevent memory leaks after the component is removed from the DOM.
The “unexpected reserved word (await)” error occurs in JavaScript when you use the await keyword in a function that is not specified as async. To fix it, add an async modifier to the function to mark it as async.
The “Unexpected reserved word ‘await'” error occurring in JavaScript.
Here’s an example of the error occurring:
index.jsCopied!
function getName() {
// ❌ SyntaxError: Unexpected reserved word
const str = await Promise.resolve('Coding Beauty');
return str;
}
Note: As this is a syntax error, the function doesn’t need to be invoked for it to be detected, and no part of the code runs until it is resolved.
The async and await keywords work together in JavaScript (hence the commonly used term, async/await); to use the await keyword in a function, you must add the async modifier to the function to specify that it is an async function.
JavaScriptCopied!
// ✅ Use "async" keyword modifier
async function getName() {
// ✅ Successful assignment - no error
const str = await Promise.resolve('Coding Beauty');
return str;
}
Fix “Unexpected reserved word (await)” error in nested function
If you’re using the await keyword, it’s likely that you already know that it has to be in an async function. What probably happened is that you nested functions and mistakenly ommited the async modifier from the innermost function containing the await keyword.
For await to work, the deepest function in the nesting hierarchy is required to be specified as async. It won’t work even if any or all of the outer functions are marked as async.
So we resolve the error in this case by adding the async modifier to the innermost function:
In this example, we should be able to remove the async keyword from the outer function, as it isn’t performing any asynchronous operations with await, but this depends on whether the caller of createTask() is expecting it to return a Promise or not.
Here’s another example where this mistake frequently happens; using await in an array looping method:
JavaScriptCopied!
// ❌ SyntaxError: Unexpected reserved word
async function processPhotos(photoIds) {
const data = await Promise.all(photoIds.map((photoId) => {
const res = await fetch(`http://example.com/photos/${photoId}`);
return await res.json();
}));
// process data...
}
Like in the previous example, the error occurs because the async keyword modifier is absent from the map() callback, even though it’s present in the function that calls map(). The fix is the same, add async to the map() callback.
JavaScriptCopied!
// ✅ No error
async function processPhotos(photoIds) {
const data = await Promise.all(
photoIds.map(async (photoId) => {
const res = await fetch(`http://example.com/photos/${photoId}`);
return await res.json();
})
);
// processing...
}
Use await at top level
If you’re trying to use await at the top level of your file, you’ll need to set the type attribute to "module" in the script tag referencing the file in the HTML. This works when your code runs in browser environments.
For example:
index.htmlCopied!
<script type="module" src="index.js"></script>
Now you’ll be able to use await at the global scope in your file, e.g.:
To handle the onScroll event on a Vue element, assign a function to the scroll event of the element and use the event object the function receives to perform an action. The action will occur whenever the user scrolls up or down on the page.
The function (event handler) passed to the scroll event is invoked whenever the viewport is scrolled. It is called with an event object, which you can use to perform actions and access information related to the scroll event.
The currentTarget property of this event object returns the element that the scroll listener was attached to.
We use the element’s scrollTop property to get how far the element’s scrollbar is from its topmost position. Then we update the state variable with the new value, and this reflects on the page.
Handle onScroll event on window object
We can also handle the onScroll event on the global window object, to perform an action when the viewport is scrolled.
type: a string representing the event type to listen for, e.g., 'click', 'keydown', 'scroll', etc.
listener: the function called when the event fires.
It also has some optional parameters, which you can learn more about here.
We call addEventListener() in the mounted hook to register the listener once the component renders as the page loads. mounted is only called for a component when it has been added to the DOM, so the listener will not be registered multiple times.
We also called the removeEventListener() method to unregister the event listener and prevent a memory leak. We place the call in the beforeUnmount hook so that it happens just before the component is removed from the DOM.
We create the boolean state with the useState hook. useState returns an array of two values, the first is the value of the state, the second is a function that updates the state when it is called.
We pass a callback function to setVisible because the callback is always passed the latest visible state.
Tip: Always pass a function to setState when the new state is computed from the current state data.
In our case, the callback simply negates the boolean value and returns the result to negate the state.
The logical NOT (!) operator converts a truthy value to false and a falsy value to true.
Note: In JavaScript there are only 6 falsy values: undefined, null, '' (empty string), NaN, 0, and false. Every other value is truthy and will result in false when negated.
Perform action on boolean state toggle
Sometimes you want to perform an action outside of re-rendering when the boolean state changes in the component, e.g., a network request. To carry out such an action, place the code in the useEffect hook and include the boolean state variable in useEffect‘s dependencies array.
The code in the useEffect hook runs after the component mounts or updates from a change in the visible state. Here, the state controls the visibility of an element, so in the hook, we check if the element is visible, and if so, we make a network request to a server to update view stats associated with the element.
Perform action on boolean state change but skip first render
Depending on your scenario, you might want the action to run when the component updates from a state change, but not it when it first mounts.
We can do this by creating a ref flag variable having an initial value of false in the first render, and change its value to true for all subsequent renders.
useRef returns a mutable ref object that doesn’t change value when a component is updated. Also, modifying the value of this object’s current property does not cause a re-render. This is in contrast to the setState update function returned from useState.
If the ref’s value is false, we prevent the action from happening in useEffect and change the value to true for the following renders. Otherwise, we execute the action.
In React apps, event listeners or observers perform certain actions when specific events occur. While it’s quite easy to create event listeners in React, there are common pitfalls you need to avoid to prevent confusing errors. These mistakes are made most often by beginners, but it’s not rare for them to be the reason for one of your debugging sessions as a reasonably experienced developer.
In this article, we’ll be exploring some of these common mistakes, and what you should do instead.
1. Accessing state variables without dealing with updates
Take a look at this simple React app. It’s essentially a basic stopwatch app, counting up indefinitely from zero.
However, when we run this app, the results are not what we’d expect:
Stuck at 1
This happens because the time state variable being referred to by the setInterval() callback/closure refers to the stale state that was fresh at the time when the closure was defined.
The closure is only able to access the time variable in the first render (which had a value of 0) but can’t access the new time value in subsequent renders. JavaScript closure remembers the variables from the place where it was defined.
The issue is also due to the fact that the setInterval() closure is defined only once in the component.
The time variable from the first render will always have a value of 0, as React doesn’t mutate a state variable directly when setState is called, but instead creates a new variable containing the new state. So when the setInterval closure is called, it only ever updates the state to 1.
Here are some ways to avoid this mistake and prevent unexpected problems.
1. Pass function to setState
One way to avoid this error is by passing a callback to the state updater function (setState) instead of passing a value directly. React will ensure that the callback always receives the most recent state, avoiding the need to access state variables that might contain old state. It will set the state to the value the callback returns.
The time is increased by 1 every second – success.
Now the time state will be incremented by 1 every time the setInterval() callback runs, just like it’s supposed to.
2. Event listener re-registration
Another solution is to re-register the event listener with a new callback every time the state is changed, so the callback always accesses the fresh state from the enclosing scope.
We do this by passing the state variable to useEffect‘s dependencies array:
Every time the time state is changed, a new callback accessing the fresh state is registered with setInterval(). setTime() is called with the latest time state added to 1, which increments the state value.
2. Registering event handler multiple times
This is a mistake frequently made by developers new to React hooks and functional components. Without a basic understanding of the re-rendering process in React, you might try to register event listeners like this:
If you do have a basic understanding of this, you should be able to already guess what this will lead to on the web page.
The seconds keep accelerating.It eventually gets as bad as this.
What’s happening?
What’s happening is that in a functional component, code outside hooks, and outside the returned JSX markup is executed every time the component re-renders.
Here’s a basic breakdown of what happens in a timeline:
1st render: listener 1 registered
1 second after listener 1 registration: time state updated, causing another re-render)
2nd render: listener 2 registered.
Listener 1 never got de-registered after the re-render, so…
1 second after last listener 1 call: state updated
3rd render: listener 3 registered.
Listener 2 never got de-registered after the re-render, so…
1 second after listener 2 registration: state updated
4th render: listener 4 registered.
1 second after last listener 1 call: state updated
5th render: listener 5 registered.
1 second after last listener 2 call: state updated
6th render: listener 6 registered.
Listener 3 never got de-registered after the re-render, so…
1 second after listener3 registration: state updated.
7th render: listener 7 registered…
Eventually, things spiral out of control as hundreds and then thousands (and then millions) of callbacks are created, each running at different times within the span of a second, incrementing the time by 1.
The fix for this is already in the first example in this article – put the event listener in the useEffect hook, and make sure to pass an empty dependencies array ([]) as the second argument.
useEffect runs after the first render and whenever any of the values in its dependencies array change, so passing an empty array makes it run only on the first render.
The time increases steadily, but by 2.
The time increases steadily now, but as you can see in the demo, it goes up by 2 seconds, instead of 1 second in our very first example. This is because in React 18 strict mode, all components mount, unmount, then mount again. so useEffect runs twice even with an empty dependencies array, creating two listeners that update the time by 1 every second.
We can fix this issue by turning off strict mode, but we’ll see a much better way to do so in the next section.
3. Not unregistering event handler on component unmount.
What happened here was a memory leak. We should have ensured that any created event listener is unregistered when the component unmounts. So when React 18 strict mode does the compulsory unmounting of the component, the first interval listener is unregistered before the second listener is registered when the component mounts again. Only the second listener will be left and the time will be updated correctly every second – by 1.
You can perform an action when the component unmounts by placing in the function useEffect optionally returns. So we use clearInterval to unregister the interval listener there.
useEffect‘s cleanup function runs after every re-render, not only when the component unmounts. This prevents memory leaks that happen when an observable prop changes value without the observers in the component unsubscribing from the previous observable value.
Conclusion
Creating event listeners in React is pretty straightforward, you just need to be aware of these caveats, so you avoid unexpected errors and frustrating debugging spells. Avoid accessing stale state variables, don’t register more event listeners than required, and always unregister the event listener when the component unmounts.