When building a gallery or content management system in React, it's common to allow users to upload images and preview them before saving. However, you may run into a scenario where:
-
Images already stored in your database are displayed with URLs like
/uploads/filename.jpg
. -
Newly selected images (not yet uploaded) are previewed using
blob:
URLs fromURL.createObjectURL(file)
. - The preview works, but after saving, your gallery doesn’t display the images properly, or the paths are inconsistent.
This article walks you through a robust solution for handling both types of images—so your gallery works seamlessly for both existing and newly uploaded files.
The Problem
-
Uploaded images: When previewing a new file, React shows a
blob:
URL. This is fine for local preview, but this URL is not valid after you reload or fetch from the server. -
Database images: When you fetch images from the backend, you get paths like
/uploads/my-photo.jpg
(or justuploads/my-photo.jpg
). These need to be shown using the full backend URL. - When you render your gallery, you need to handle both cases in your preview and display logic.
The Solution Strategy
-
For files already in the database:
- Store only the relative path (e.g.,
uploads/my-photo.jpg
) in your database. - When rendering, prepend your backend host (e.g.,
https://your-backend.com/
orhttp://localhost:5001/
) to the path.
- Store only the relative path (e.g.,
-
For new images (before upload):
- Use
URL.createObjectURL(file)
to generate a temporary preview. - These URLs start with
blob:
and should be used as-is.
- Use
-
In your React component:
- Create a helper function that checks if the image source is a
blob:
or a server path. - If it’s a server path, prepend your API URL. If it’s a blob, use it directly.
- Create a helper function that checks if the image source is a
Example Implementation
const API = import.meta.env.VITE_OPEN_APIURL; // Your backend URL
// Helper function to get the correct image URL for preview
function getImageSrc(src) {
if (!src) return "";
if (src.startsWith("blob:")) return src; // New file preview
// Remove starting slash if present
const cleanSrc = src.replace(/^(\/+)/, "");
// If already absolute (e.g., https://), return as is
if (/^https?:\/\//.test(src)) return src;
return `${API}/${cleanSrc}`; // Database images
}
Usage in Your Component
// Example galleryImgs state
const [galleryImgs, setGalleryImgs] = useState([
// Existing image from DB
{ src: "uploads/image1.jpg", file: null, isOld: true },
// New image being previewed
{ src: "blob:http://localhost:5173/abc-123", file: FileObj, isOld: false }
]);
// Rendering
<div className="flex flex-wrap gap-4 mt-4">
{galleryImgs.map((img, idx) => (
<img
key={idx}
src={getImageSrc(img.src)}
alt=""
className="w-24 h-24 object-cover rounded-2xl"
/>
))}
</div>
Additional Tips
- Always store relative paths (like
uploads/my-photo.jpg
) in your database, not absolute URLs. - Use your backend’s host URL as a constant in your frontend, and prepend it for image display.
- Clean paths that start with a slash, so you don't end up with double slashes in the URL.
- Clean up blob URLs using
URL.revokeObjectURL()
when the image is removed from the preview to avoid memory leaks.
Conclusion
With this approach, your React gallery will correctly preview both newly added images and those already stored in your database, providing a smooth and professional user experience.
Always handle image URLs carefully, and your gallery will look great and work perfectly—no matter how your users interact with it!
Top comments (0)