Understanding Side Effects in JavaScript
When writing JavaScript, you’ve likely encountered situations where a function doesn’t just return a value, it does something else too, like updating the DOM or saving the data. That something else
is called a side effect.
To better understand side effects, you need to understand the pure and impure functions concept.
Pure Function
This is a function that, when given the same inputs, it always returns the same output. It also does not cause any side effects (like modifying a global variable, changing an input parameter, logging to the console, writing to a file, etc).
Think of it like a mathematical function: If you call
f(2)
and get4
, you’ll always get4
when you callf(2)
again.
function add(a, b) {
return a + b;
}
Calling add(2, 3)
will always return 5
. It does not modify anything outside itself, and It does not rely on or alter external state.
Impure Function
This type of function may return different outputs for the same inputs (because it relies on external state or random values). It has side effects, that is, it changes something outside itself: logging, modifying a database, or updating a global variable, etc.
let total = 0;
function addToTotal(amount) {
// Impure: modifies external variable
total += amount;
return total;
}
But what exactly is a side effect? Why do they matter? And how can you manage them effectively in your codebase?
What Is a Side Effect?
In programming, a side effect occurs when a function interacts with the outside component or modifies something outside its own scope.
A side effect is any change in the function flow that happens outside of the current function.
This includes things like:
- Updating a variable that exists outside the function
- Changing the DOM
- Making a network request
- Logging to the console
- Modifying or writing to the database
Why Are Side Effects Important?
Side effects are not inherently bad. In fact, all useful programs have side effects. Otherwise, they'd just compute values and never do anything with them.
But uncontrolled side effects can lead to problems:
- Less predictable behaviour
- Bugs from shared state
- Debugging nightmares
That’s why developers often try to isolate or minimize side effects for better code quality.
Examples of Side Effects in JavaScript
Let’s go through a few use cases of side effects so you can identify them in your code.
- Changing a Global Variable
let count = 0;
function increment() {
// Side effect: modifies external variable
count += 1;
}
- Manipulating the DOM
function changeHeading() {
// Side effect
document.getElementById("title").innerText = "New Title";
}
- Making an API Call
function fetchData() {
// Side effect: HTTP request
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data));
}
- Logging to the Console
function logUser(name) {
// Side effect: output to console
console.log(`User: ${name}`);
}
Managing Side Effects in Your Apps
In frameworks like React, developers manage side effects using hooks like useEffect
.
Example:
import { useEffect } from "react";
function Page() {
useEffect(() => {
// Side effect managed in lifecycle
document.title = "React Page";
}, []);
return <h1>Hello</h1>;
}
This approach demonstrates how React handles operations that interact with the outside components, known as side effects
, predictably using hooks. By placing the side effect inside useEffect
, the component remains focused on rendering the UI, while all external interactions are handled separately. This separation leads to cleaner, more maintainable code, as side effects are clearly distinguished from pure rendering logic, making it easier to reason about component behaviour and lifecycle events.
Final Thoughts
Side effects are everywhere, and they’re not evil.
The real challenge is knowing when and how to use them properly.
The more you can separate what your code calculates from what it does, the easier it becomes to maintain, test, and scale your JavaScript applications.