It's Day #8 of the #100daysofMiva coding challenge. See codes on GitHub
Today, I worked on a simple image slider project using React. The project involved fetching images from an external API and displaying them in a slider format, where users can navigate through the images using left and right arrow buttons. Below is a breakdown and analysis of the code and what I learned from this experience.
Code Analysis
Let's break down the code step by step:
1. Import Statements
import { useEffect, useState } from "react";
import { BsArrowLeftCircleFill, BsArrowRightCircleFill } from "react-icons/bs";
import "./styles.css";
useEffect
and useState
are hooks provided by React to handle side effects and state management, respectively.
BsArrowLeftCircleFill
and BsArrowRightCircleFill
are icon components imported from the react-icons library. These are used to display the navigation arrows.
./styles.css
imports the CSS file that contains the styles for the slider.
2. Component Definition
export default function ImageSlider({ url, limit = 5, page = 1 }) {
const [images, setImages] = useState([]);
const [currentSlide, setCurrentSlide] = useState(0);
const [errorMsg, setErrorMsg] = useState(null);
const [loading, setLoading] = useState(false);
ImageSlider
is a React functional component that receives three props: url
, limit
, and page
. The url
prop specifies the API
endpoint to fetch images from. limit
and page
are optional props with default values, determining how many images to fetch and which page of the API
to request.
Four pieces of state are managed using useState:
images
: Stores the fetched image data.
currentSlide
: Tracks the currently displayed image.
errorMsg
: Stores any error message if the image fetching fails.
loading
: Indicates whether the images are currently being loaded.
3. Fetching Images
async function fetchImages(getUrl) {
try {
setLoading(true);
const response = await fetch(`${getUrl}?page=${page}&limit=${limit}`);
const data = await response.json();
if (data) {
setImages(data);
setLoading(false);
}
} catch (e) {
setErrorMsg(e.message);
setLoading(false);
}
}
fetchImages
is an asynchronous function that fetches image data from the provided API url.
setLoading(true)
is called before the fetch to indicate that data is being loaded.
The fetch
function retrieves the data from the API, and await response.json()
parses it into a JavaScript object. If data is successfully fetched, it is stored in the images state.
If an error occurs, setErrorMsg
is called to store the error message, and loading is stopped.
4. Navigating Between Images
function handlePrevious() {
setCurrentSlide(currentSlide === 0 ? images.length - 1 : currentSlide - 1);
}
function handleNext() {
setCurrentSlide(currentSlide === images.length - 1 ? 0 : currentSlide + 1);
}
handlePrevious
and handleNext
are functions to navigate through the images.
handlePrevious
decreases the currentSlide
index unless it’s at the first image, in which case it loops back to the last image.
handleNext
increases the currentSlide
index unless it’s at the last image, in which case it loops back to the first image.
5. Fetching Images on Component Mount
useEffect(() => {
if (url !== "") fetchImages(url);
}, [url]);
useEffect
is used to run fetchImages
when the component mounts or whenever the url
prop changes. This ensures that new images are fetched if the url changes.
6. Rendering the Component
if (loading) {
return <div>Loading data! Please wait</div>;
}
if (errorMsg !== null) {
return <div>Error occurred! {errorMsg}</div>;
}
If loading
is true, a loading message is displayed. If errorMsg
contains a value, the error message is displayed.
7. Image Slider Display
return (
<div className="container">
<BsArrowLeftCircleFill
onClick={handlePrevious}
className="arrow arrow-left"
/>
{images && images.length
? images.map((imageItem, index) => (
<img
key={imageItem.id}
alt={imageItem.download_url}
src={imageItem.download_url}
className={
currentSlide === index
? "current-image"
: "current-image hide-current-image"
}
/>
))
: null}
<BsArrowRightCircleFill
onClick={handleNext}
className="arrow arrow-right"
/>
<span className="circle-indicators">
{images && images.length
? images.map((_, index) => (
<button
key={index}
className={
currentSlide === index
? "current-indicator"
: "current-indicator inactive-indicator"
}
onClick={() => setCurrentSlide(index)}
></button>
))
: null}
</span>
</div>
);
The main slider is rendered within a div with the class container. The left and right arrows call handlePrevious
and handleNext
respectively to change the displayed image. The current image is shown using an img
tag, and non-current images are hidden using the hide-current-image
class. Circle indicators below the images represent each slide, and the active slide is highlighted.
CSS Analysis
The CSS is used to style the slider:
.container
: Centers the content and sets the slider size.
.current-image
:
Styles the displayed image.
.arrow
: Positions the navigation arrows.
.circle-indicators
: Positions the indicator buttons at the bottom.
.current-indicator
: Styles the active slide indicator.
.hide-current-image
: Hides non-active images.
.inactive-indicator
: Styles the inactive slide indicators.
Top comments (2)
Beautiful 🪄
Thank you