I often find myself wondering where to store images in React app. Especially when I'm starting a new project. I decided to do a little bit of research to find out what options for storing images are available. And what are the drawbacks and benefits that come with each method? I decided to list everything I learned in this article. And I'll also show some tips & tricks related to the handling of images.
There are 3 main approaches to store images in react app:
-
src
folder - Images stored in this directory will be included in the final bundle. Additionally, they have the added bonus of being able to be imported as a JavaScript module. -
public
folder - Files inpublic
directory will not be processed by Webpack. And they won't be a part of the final bundle. - External server - Images can also be stored on external servers like S3 or Cloudinary and referenced from the react application.
To see what the pros and cons of each method are, we'll have to take a closer look at each one separately.
3 Ways to Store Images in React App
Images are an important part of React application. It is important to store them in a reliable way, so that future development is not hampered by any data loss. Here are 3 of the most popular methods for storing images in React apps.
Storing Images in Source Directory
Saving images in src
directory is a good solution and it is oftentimes encouraged to use instead of the static file serving. Most react developers tend to store their images in src/assets
folder. In React, you can import images as a data property that's stored in a JavaScript object. These data properties are accessible anywhere in your component.
Pros
- All the images are processed by Webpack so we can provide further optimizations
- Good if image content is changing a lot due to Webpack hashing
- Possibility to use the image as a javascript module
Cons
- Dynamic imports of images can cause problems
Serving Images as Static Assets
Static assets, such as images, scripts, and videos, are files that are stored on a website's server and served to users. A static image can be displayed on a website without requiring any additional resources. These resources can be JavaScript, Flash, or other browser plugins.
Pros
- The file is located on the same server as the main app which can improve performance
- Easy to load files dynamically
Cons
- Not processed by Webpack so we can't perform optimizations
- We need to change the name of the image if the content changes because of the caching
- Missing files will not be called at compilation time, and will cause 404 errors
Storing Images on External Server
The third option is to use an external service such as Cloudinary or Amazon S3. Cloudinary or S3 are both services that take care of all of the heavy lifting when it comes to the image hosting for developers. Using these services, we can focus on coding and don't have to worry about storing and processing images.
Pros
- Image management is handled by the specialized service
- Optimized CDN to serve images as fast as possible
Cons
- Not suitable for projects with a low budget
- We need to change the name of the image if the content changes because of the browser cache.
How to Lazy Load Images
Lazy loading images is a technique used in web development to save data and increase loading speed. It improves the performance of any website and makes it more in the terms of managing its resources. There are two steps to lazy loading images:
- Dynamically generating the
src
attribute of animg
tag so that it is not set until the image is visible in the browser - Setting rules for when
src
attribute of animg
should be set to a given value. In most cases, this rule is set to an image entering the browser's viewport.
The lazy loading technique is often used on social media sites so that they don't load all of the images at once. This will allow them to present their website with a more appealing layout, as well as save time and bandwidth for users. Now that we know what lazy loading is, let's see how can we implement it in our beloved React.
Lazy Loading Images in React
Lazy loading images in React can be done by using the IntersectionObserver API. This API provides an asynchronous way to observe changes on the web page and let you know when an element crosses a given threshold. In other words, we can monitor when the element enters or leaves the viewport. So we can load an image or just any other resource.
To implement this behavior, we can make use of an awesome library called react-lazyload. With the help of react-lazyload
the images get loaded only when they come to the user's eye. It works by listening to the window scroll event and checking if any new image has appeared in the browser viewport. The library makes sure that an image is visible before it loads it in order to avoid unnecessary pixelation or unwanted memory usage.
The usage is very simple. All we need to do is wrap the img
with LazyLoad
component and everything works out of the box.
import React from "react";
import LazyLoad from "react-lazyload";
import image from "./image.jpg";
const App = () => {
/**
* Lazy loading images is supported out of box, no extra config is needed
* `height` is set for better experience
*/
return (
<LazyLoad height={200}>
<img src={image} />
</LazyLoad>
);
};
export default App;
Load Images Progressively
Progressive image loading is a technique that displays a low-resolution image first. Then gradually replaces it with higher-resolution versions of the same image. One reason for the use of progressive image loading is the need to conserve bandwidth, but it also allows a viewer to get a quick preview of the image before it loads in full resolution.
While this technique is usually used for image formats like PNG or JPEGs. It can be used for animated GIFs as well, where the animation would be displayed at low resolution first and then replaced by higher-resolution frames.
Progressive Loading in React
Progressive image loading can be done with a few lines of code. But there are also libraries available for React like react-progressive-image that can do all the work for us with as little effort as possible. This module is a popular choice for progressive image loading in React applications. It provides a higher-order component that accepts src
and placeholder
properties.
import React from "react";
import ProgressiveImage from "react-progressive-image";
import image from "./image.jpg";
import placeholderImage from "./placeholderImage.jpg";
const App = () => {
/**
* `placeholder` will be displayed
* while the original `src` image is being loaded
*/
return (
<ProgressiveImage src={image} placeholder={placeholderImage}>
{(src) => <img src={src} alt="an image" />}
</ProgressiveImage>
);
};
export default App;
The example above will initially display placeholder
which is in most cases a very tiny version of an original image. The browser will load it much faster than the original image. However, we still need to load the placeholder from the server. To save us this trouble, we can directly use the base64 encoded image as the placeholder
.
import React from "react";
import ProgressiveImage from "react-progressive-image";
import image from "./image.jpg";
import placeholderImage from "./placeholderImage.jpg";
const App = () => {
return (
<ProgressiveImage src={image} placeholder="data:image/png;base64***">
{(src) => <img src={src} alt="an image" />}
</ProgressiveImage>
);
};
export default App;
Importing Images Dynamically
In this section, we are going to learn how to import images dynamically in React. I faced this problem many times in my career as a developer. And I also saw other people struggling with it as well.
In order to use an image in React app, we need to import it first. So the problem we are trying to solve is simple. How can we import something dynamically? Believe it or not, the solution is simple as well. All we need to do is implement a component that will take the name of the file as a prop
. And returns img
element with the src
set to the given image.
import React from "react";
const Image = ({ name }) => {
try {
// Import image on demand
const image = require(`assets/${name}`);
// If the image doesn't exist. return null
if (!image) return null;
return <img src={image.default} />;
} catch (error) {
console.log(`Image with name "${name}" does not exist`);
return null;
}
};
export default Image;
The component takes the name of the file and tries to import it. If the file with the given name doesn't exist. The execution fails and will be caught by our catch
block. It's a good idea to show a warning, so people using this component see something is not in order.
Conclusion
Images are a common component in websites. There are many different ways to store images in React application and it's important to understand the pros and cons of all of them. In this blog post, we looked at different ways of storing images in react app and found a good application for each method.
I also shared some tips and tricks, along with the best practices that should be applied when it comes to working with images. These practices contain methods like lazy-loading or progressive loading. Now for the final part, it's time to take these methods and start using them in your React project.
Top comments (3)
On Storing Images in Source Directory the con is Dynamic imports of images can cause problems, could you provide some examples?
Thanks for asking. If you use dynamic imports, you can use that file easily in js file. But id you try to use it in CSS, for example setting background image. It's a bit trickier. You'll have to first improt it with webpack. And the use the webpack generater url as the background in CSS file.
Got it! Thank you.