Dealing with APIs often requires sending clean data objects—free from null, undefined, or empty strings. Instead of manually checking every property, you can automate this process with a recursive "clean" function.
In this guide, we'll build a robust utility to sanitize your JavaScript objects, ensuring your API payloads are always lean and valid.
null values.This function deep-cleans an object by traversing all levels of nesting, including arrays.
While you can do this with vanilla JS, Lodash provides excellent deep cloning and object manipulation utilities that handle edge cases (like circular references) more gracefully.
npm install lodashimport _ from "lodash";
/**
* Recursively removes null, undefined, and empty string values from an object.
* Also handles empty objects and arrays resulting from the cleaning process.
*/
export const cleanObject = (obj) => {
// Create a deep copy to maintain immutability
const copy = _.cloneDeep(obj);
const clean = (data) => {
// Return primitive values as-is
if (typeof data !== "object" || data === null) {
return data;
}
// Handle Arrays
if (Array.isArray(data)) {
return data
.map((item) => clean(item))
.filter((item) => item !== null && item !== undefined && item !== "");
}
// Handle Objects
const newObj = {};
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
const value = data[key];
// Skip null, undefined, or empty strings
if (value === null || value === undefined || value === "") {
continue;
}
const cleanedValue = clean(value);
// Skip empty arrays or empty objects created by the cleaning process
if (Array.isArray(cleanedValue) && cleanedValue.length === 0) continue;
if (
typeof cleanedValue === "object" &&
cleanedValue !== null &&
Object.keys(cleanedValue).length === 0
) {
continue;
}
newObj[key] = cleanedValue;
}
}
return newObj;
};
return clean(copy);
};Let's see how it handles a complex, "dirty" object:
const dirtyObject = {
name: "John Doe",
email: "", // Should be removed
age: 30,
preferences: null, // Should be removed
address: {
street: "123 Main St",
city: "", // Should be removed
details: {
apt: null, // Should be removed
},
},
tags: ["react", null, "javascript", ""], // Should clean array
};
const cleanData = cleanObject(dirtyObject);
/*
Result:
{
name: "John Doe",
age: 30,
address: {
street: "123 Main St"
},
tags: ["react", "javascript"]
}
*/If you prefer not to use external libraries, here is a lightweight version for modern browsers:
export const cleanObjectVanilla = (obj) => {
return Object.fromEntries(
Object.entries(obj)
.filter(([_, v]) => v != null && v !== "")
.map(([k, v]) => [
k,
v === Object(v) && !Array.isArray(v) ? cleanObjectVanilla(v) : v
])
.filter(([_, v]) =>
v !== null &&
(typeof v !== "object" || Object.keys(v).length > 0)
)
);
};Date objects, as typeof date === 'object'. You might need to add a check for data instanceof Date.Cleaning your data objects is a small step that leads to much more reliable and maintainable code. Whether you use the Lodash version for maximum robustness or the Vanilla JS version for zero dependencies, your APIs will thank you!
Integrate the clean function into your React application:
// App.js
import { cleanObject } from "./cleanObject";
import { dirtyObject } from "./dummyData";
import "./styles.css";
export default function App() {
console.log("dirty", dirtyObject);
const cleanedObject = cleanObject(dirtyObject);
console.log("cleanedObject", cleanedObject);
return (
<div className="App">
<h1>Object Cleaning Demo</h1>
<div>
<h2>Original Object</h2>
<pre>{JSON.stringify(dirtyObject, null, 2)}</pre>
</div>
<div style={{ marginTop: "50px" }}>
<h2>Cleaned Object</h2>
<pre>{JSON.stringify(cleanedObject, null, 2)}</pre>
</div>
</div>
);
}After cleaning, your object will look like this:
{
"name": "John Doe",
"age": 30,
"address": {
"street": "123 Main St"
},
"hobbies": [
"coding",
"reading",
{
"age": 333,
"hobbies": ["2", 3]
}
]
}By following these steps, you can ensure your objects are cleaned of null, undefined, and empty values before sending them to your backend. This approach:
This pattern is especially useful when working with forms, API requests, and data validation in modern JavaScript applications.
More articles you might find interesting
Learn how to implement recursion in React components to manage nested radio button groups using JavaScript's Map object for efficient state management.
Have you ever tried to log or send state immediately after calling its set function, only to find the old value instead? This is one of the most common "aha!" moments for React developers.
Discover why using array indices as keys in React can lead to performance issues and bugs, and learn the best practices for proper list rendering.