Building a Progressive Image Gallery in React with TypeScript
This challenge focuses on implementing a React component that displays a gallery of images. The core requirement is to build this component with progressive enhancement in mind: it should function gracefully even when JavaScript is disabled, and provide an increasingly richer experience as JavaScript capabilities become available. This is a crucial skill for building robust and accessible web applications.
Problem Description
You are tasked with creating a ImageGallery React component that displays a list of image URLs. The component should initially render a simple list of image links (accessible even without JavaScript). As JavaScript becomes available, the component should progressively enhance the experience by:
- Loading Images with Placeholders: Display a placeholder image (e.g., a grey box) while the actual image is loading.
- Error Handling: Display an error message if an image fails to load.
- Lazy Loading (Optional): Implement lazy loading for images that are not currently visible in the viewport. This is a bonus challenge.
The component should accept an array of image URLs as a prop.
Key Requirements:
- No JavaScript: The component should render a basic list of image links if JavaScript is disabled. Users should still be able to access the images directly.
- Placeholder Images: When JavaScript is enabled, display a placeholder image while the actual image is loading.
- Error Handling: If an image fails to load, display an appropriate error message instead of a broken image icon.
- Accessibility: Ensure the component is accessible, with appropriate
altattributes for images and meaningful error messages. - TypeScript: The component must be written in TypeScript.
Expected Behavior:
- JavaScript Disabled: A simple unordered list of image links is rendered.
- JavaScript Enabled: An ordered list of image containers is rendered. Each container displays a placeholder image while the actual image loads. If the image fails to load, an error message is displayed.
Edge Cases to Consider:
- Empty image URL array.
- Invalid image URLs.
- Network errors during image loading.
- Very large image URLs (consider performance implications).
Examples
Example 1:
Input: imageUrls = ["https://via.placeholder.com/150", "https://via.placeholder.com/200", "https://via.placeholder.com/250"]
Output: (JavaScript Enabled) A list of three image containers, each displaying a placeholder while the image loads, then the actual image.
Explanation: The component renders a list of image containers. Each container initially shows a placeholder, then loads the image from the provided URL.
Example 2:
Input: imageUrls = ["https://via.placeholder.com/150", "invalid-url", "https://via.placeholder.com/250"]
Output: (JavaScript Enabled) The first and third images load successfully. The second image container displays an error message.
Explanation: The component handles invalid URLs gracefully by displaying an error message instead of a broken image.
Example 3:
Input: imageUrls = []
Output: (JavaScript Enabled & Disabled) An empty list.
Explanation: The component handles the case where the input array is empty.
Constraints
- Image Size: Assume image sizes will be reasonable (up to 2MB).
- Error Handling: Implement basic error handling for image loading failures. Detailed error reporting is not required.
- Performance: While lazy loading is optional, consider the performance implications of loading many images at once.
- Dependencies: You are allowed to use standard React and TypeScript features. External libraries for image loading or lazy loading are discouraged (but not strictly prohibited). If you use external libraries, justify your choice.
Notes
- Start by implementing the basic functionality (list of image links when JavaScript is disabled).
- Then, progressively add the enhancements (placeholders, error handling).
- Consider using React's
useEffecthook to handle image loading. - Think about how to provide a good user experience even when images fail to load.
- The placeholder image can be a simple colored box or a more sophisticated loading indicator.
- For the optional lazy loading challenge, research React libraries or techniques for implementing lazy loading. Intersection Observer API is a good starting point.