Master media in React by learning to handle loading states, implement smart fallbacks for broken images, and optimize your assets for better performance.
Previously in this course, we explored building a favorites list to manage complex state. This lesson shifts our focus to the visual layer of our movie-browser app: rendering external media.
In a professional application, you cannot assume an image will always load instantly—or even load at all. Network latency, broken API links, and slow connections are facts of life. To build a truly modern UI, you must handle these scenarios gracefully.
In React, the <img> tag is just an HTML element, but when it points to an external source, it behaves like an asynchronous operation. The browser begins downloading the file, and during this time, the component is in a "loading" state.
If the server returns a 404 or the URL is malformed, the browser fires an onError event. If we ignore these events, we end up with "broken" UI—empty white rectangles or ugly browser-default icons that ruin the user experience.
Instead of placing raw <img> tags throughout your app, it is a best practice to create a reusable MoviePoster component. This encapsulates the logic for loading states and error fallbacks.
JSXimport { useState } from CE9178">'react'; const MoviePoster = ({ src, alt, title }) => { const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); // Fallback image if the API returns a broken link const fallbackSrc = CE9178">'/placeholder-movie.png'; return ( <div className="poster-container"> {isLoading && <div className="spinner">Loading...</div>} {!hasError ? ( <img src={src} alt={alt} onLoad={() => setIsLoading(false)} onError={() => { setHasError(true); setIsLoading(false); }} style={{ display: isLoading ? CE9178">'none' : CE9178">'block' }} /> ) : ( <img src={fallbackSrc} alt="Placeholder" /> )} </div> ); };
onLoad Event: This fires once the browser has successfully fetched the image. We use it to set isLoading to false, revealing the image only after it's ready.onError Event: This is your safety net. If the image fails to load, we update our state to swap the broken source for a local, reliable placeholder.style={{ display: isLoading ? 'none' : 'block' }}. This ensures the browser doesn't show a "broken" icon while the image is still being fetched.Rendering high-resolution images for every device is a performance killer. While advanced image optimization usually happens on the server (using CDNs like Cloudinary or Imgix), you can contribute at the component level:
loading="lazy" attribute to your <img> tags. This tells the browser to wait until the image is near the viewport before downloading it, significantly improving initial page load times.aspect-ratio to reserve space for the image before it loads. This prevents "layout shift," where the page content jumps around as images pop into existence.Update your MovieCard component in the movie-browser project to use a custom MoviePoster component.
MoviePoster.jsx.img tag logic into this component.onLoad and onError handlers as shown above.poster-container that sets a consistent aspect-ratio: 2/3 to keep your movie grid perfectly aligned while images load.onError: Never set the src to the same URL that failed inside the onError handler. This will cause an infinite loop of error events. Always point to a local, static fallback image.alt tag. If the image is decorative, use alt="". If it's a movie poster, use the movie title.Handling media in React is about anticipating the unpredictable nature of the network. By managing images with dedicated state for loading and errors, you create a resilient interface. Remember to use loading="lazy" to keep your app performant and ensure you provide fallbacks to prevent empty UI blocks.
Up next: We will begin our unit testing journey, starting with an introduction to testing our React components.
Learn how to initialize a professional React project using Vite. We’ll cover the project directory structure and how to launch your fast development environment.
Read moreMaster project finalization by learning systematic QA, bug squashing, and UX refinement techniques to ensure your React movie browser is production-ready.
Handling Media in React