React Image Gallery with Dynamic Loading
Build a responsive image gallery component in React using TypeScript. This gallery should efficiently load and display images, allowing users to browse through a collection. The challenge focuses on implementing core gallery features, including image display, selection, and a basic loading mechanism.
Problem Description
Your task is to create a React component that functions as an image gallery. This component will receive an array of image objects, each containing at least a url and an id. The gallery should display these images in a grid layout. Users should be able to click on an image to select it, visually indicating that it's active. For larger collections, implement a simple "load more" functionality to fetch additional images.
Key Requirements:
- Image Display: Render images from a given data source in a responsive grid.
- Image Selection: Allow users to click on an image to select it. The selected image should have a distinct visual style (e.g., a border, overlay). Only one image should be selectable at a time.
- Dynamic Loading: Implement a "Load More" button. When clicked, this button should fetch and display the next set of images.
- TypeScript: The entire solution must be written in TypeScript.
Expected Behavior:
- Initially, a subset of images should be displayed.
- Clicking an unselected image should select it and deselect any previously selected image.
- Clicking a selected image should deselect it.
- Clicking the "Load More" button should append more images to the gallery.
Edge Cases:
- What happens if the initial data is empty?
- What happens when there are no more images to load? The "Load More" button should be disabled or hidden.
Examples
Example 1: Initial Load
Input:
const images = [
{ id: 'img1', url: 'https://example.com/image1.jpg' },
{ id: 'img2', url: 'https://example.com/image2.jpg' },
{ id: 'img3', url: 'https://example.com/image3.jpg' },
{ id: 'img4', url: 'https://example.com/image4.jpg' },
{ id: 'img5', url: 'https://example.com/image5.jpg' },
];
const initialLoadCount = 3; // Assume this is passed as a prop or internal state
Output (Visual Representation):
A grid displaying image1.jpg, image2.jpg, image3.jpg.
A "Load More" button is visible.
No image is selected.
Explanation: The gallery initially loads initialLoadCount images.
Example 2: After Clicking "Load More" and Selecting an Image
Input (State after Example 1 and loading more):
// Internal state after loading more
const loadedImages = [
{ id: 'img1', url: 'https://example.com/image1.jpg' },
{ id: 'img2', url: 'https://example.com/image2.jpg' },
{ id: 'img3', url: 'https://example.com/image3.jpg' },
{ id: 'img4', url: 'https://example.com/image4.jpg' },
{ id: 'img5', url: 'https://example.com/image5.jpg' },
];
const selectedImageId = 'img2';
Output (Visual Representation):
A grid displaying image1.jpg, image2.jpg, image3.jpg, image4.jpg, image5.jpg.
image2.jpg has a distinct selected style (e.g., a prominent border).
The "Load More" button is visible (assuming more images are available).
Explanation: After clicking "Load More", the next set of images is displayed. image2 was then clicked and is now visually marked as selected.
Example 3: No More Images to Load
Input (State after loading all images):
const loadedImages = [
{ id: 'img1', url: 'https://example.com/image1.jpg' },
{ id: 'img2', url: 'https://example.com/image2.jpg' },
{ id: 'img3', url: 'https://example.com/image3.jpg' },
{ id: 'img4', url: 'https://example.com/image4.jpg' },
{ id: 'img5', url: 'https://example.com/image5.jpg' },
];
const selectedImageId = 'img4';
const allImagesLoaded = true; // Flag indicating no more images
Output (Visual Representation):
A grid displaying image1.jpg, image2.jpg, image3.jpg, image4.jpg, image5.jpg.
image4.jpg has a distinct selected style.
The "Load More" button is not visible or is disabled.
Explanation: All available images are displayed. Since allImagesLoaded is true, the "Load More" functionality is deactivated.
Constraints
- The
imagesprop will be an array of objects, where each object has at least anid(string) and aurl(string). - The
initialLoadCountprop will be a positive integer. - The number of images to load each time the "Load More" button is clicked will be consistent (e.g., always load 3 more images).
- Assume the data fetching for "Load More" is simulated and doesn't require actual network requests for this challenge. You can manage the state of available images and loaded images internally.
- The gallery should be reasonably responsive, adapting to different screen sizes.
Notes
- Consider how you will manage the state for the currently displayed images and the selected image within your React component.
- Think about how to simulate the "loading more" functionality. You might need to keep track of the index or count of already loaded images.
- Styling for the selected image is up to your creativity, but it should be clearly distinguishable from unselected images.
- For the grid layout, consider using CSS Grid or Flexbox.
- You can define a type for your image objects for better TypeScript support.