I have encountered a challenge while working on a react file-upload component. The issue at hand is relatively simple - I aim to display an icon corresponding to the file extension for each uploaded file. These icons are loaded through css as background images (using inline styles). However, a problem arises when there is no specific icon available for a particular extension, and I need to show a fallback icon.
One approach I attempted was using multiple css background-image declarations like so:
style={{
backgroundImage: `url(./icons/fallback.svg), url(./icons/${item.extension}.svg)`,
}}
or alternatively:
style={{
backgroundImage: `url(./icons/fallback.svg)`,
backgroundImage: `url(./icons/${item.extension}.svg)`,
}}
However, this method did not produce the desired results; either the fallback icon was not displayed or both icons were shown simultaneously, which was not what I intended.
I attempted to check if the file exists by fetching it, but my node server (utilized in create-react-app) always returns a 200 or 304 response even if the file is non-existent.
To address this issue, I explored a possible solution involving creating an image object with onload
and onerror
events, as proposed in this question. While this workaround worked well, refactoring the function to simply return a boolean proved challenging. Although using callbacks and console.log()
worked fine, attempting to directly return a boolean resulted in undefined
, likely due to the asynchronous nature of Image methods. I considered leveraging the Promise API to resolve this but faced obstacles in implementation.
The code snippet demonstrating my attempt:
exists = src => {
const checks = {};
return callback => {
if (src in checks) {
return callback(checks[src]);
}
let img = new Image();
img.onload = function() {
checks[src] = true;
callback(true);
};
img.onerror = function() {
checks[src] = false;
callback(false);
};
img.src = src;
};
};
The render method utilized:
render() {
// Function logs as expected, but practical usage is limited
console.log(this.exists('./icons/jpg.svg')(bool => {
if(bool) {
console.log('yes')
} else {
console.log('no');
}
}));
// ...
}
While trying to directly return a boolean, the outcome is undefined:
render() {
console.log(this.exists('./icons/jpg.svg')(bool => bool));
// ...
}