DEV Community

loading...

Help with Image Click Through (Like a Carousel) using React Hooks

mitchelln11 profile image mitchelln11 ・2 min read

I have a component that is similar to a carousel, only I'm just clicking through using React Hooks. I have a full-width image with a left and a right click arrow. (I only have the right arrow click for now. Also not worrying about conditionals just yet.)

  1. I am setting the images in the useState
  2. Setting the default image to be the 0 index of the state values.
let indexValue = 0; // Initial slide index value
    let currentSlide = slides[indexValue];

Image, alt, and title display properly, cool.

  1. Created a right arrow click function that's supposed to update the image.
    const arrowRightClick = () => {
        currentSlide = slides[indexValue + 1];
        console.log(currentSlide);
    }

When I click on the right arrow, the console log does indeed display the next image, img2.jpg, however, the image itself never updates.

??? What am I doing wrong?

I feel like I have to do useEffect somewhere.
I've tried this(doesn't work):

useEffect(() => {
        function changeSliderImage(currentSlide) {
            setSlides(currentSlide.setSlides);
        }
        return () => {
        <img src={currentSlide.source} alt={currentSlide.title} title={currentSlide.title} className="slider-img" />
    }
    }, [])

I feel like it's close to something like the previous code, but I'm not sure.

Full code below:

import React, { useState, useEffect } from 'react';

function Carousel() {

    const [slides, setSlides] = useState([
        {
            source: "../images/img1.jpg",
            title: "Half Moon Pier"
        },
        {
            source: "../images/img2.jpg",
            title: "Port Washington Rocks"
        },
        {
            source: "../images/img3.jpg",
            title: "Abandoned Rail"
        }
    ]);

    let indexValue = 0; // Initial slide index value
    let currentSlide = slides[indexValue]; // variable index value we can reference later

    // Index value moves up, but doesn't update the image. Why???
    const arrowRightClick = () => {
        currentSlide = slides[indexValue + 1];
        console.log(currentSlide);
    }

    return (
        <div className="carousel-block">
            <div className="flex-container">
                <div id="slider">
                    <div className="slide">
                        <img src={currentSlide.source} alt={currentSlide.title} title={currentSlide.title} className="slider-img" />
                        <div className="arrows">
                            <div id="arrow-left"><i className="fas fa-arrow-alt-circle-left"></i></div>
                            <div id="arrow-right" onClick={arrowRightClick}><i className="fas fa-arrow-alt-circle-right"></i></div>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    )
}

export default Carousel;

Any help would be appreciated

Discussion

pic
Editor guide
Collapse
mitchelln11 profile image
mitchelln11 Author

For those who might come across this later, I figured out my own problem.

  1. We are use state, so import React with useState:

import React, { useState } from 'react';

  1. Create your main function that you will be exporting
function Carousel() {
}

OR *(If you're going by ES6)*

const Carousel = () => {
}
  1. Inside the function, create your variable as an object (Not actually changing state, so we don't need a function to change anything.(Make sure your image paths are correct)
    const [slides] = useState([
        {
            source: "../images/img1.jpg",
            title: "Image 1"
        },
        {
            source: "../images/img2.jpg",
            title: "Image 2"
        },
        {
            source: "../images/img3.jpg",
            title: "Image 3"
        }
    ]);
  1. Typically, when we set images, we'd do something like this:
<img src="../images/img1.jpg" alt="Image 1" title="Image 1" className="slider-img" />

But because it's React, we want the images to be dynamic, so we should opt for something like this:

<img src={currentSlide.source} alt={currentSlide.title} title={currentSlide.title} className="slider-img" />
  1. The above won't do anything yet, because currentSlide is not declared. Now we have to set defaults.
    let [currentPosition, setCurrentPosition] = useState(0); // Initial slide index value
    let currentSlide = slides[currentPosition]; // variable index value we can reference later

Because we want to change something, we need another variable to act as our indexer(currentPosition). I had issues when setting this to const, so even though though React Docs use const, the variable is changing, so I changed it to let to get past the error of setting it to const.

currentPosition is my indexer
currentslide is all of my information inside each index of the slides variable object.

With this, the first image should display on the page. (That is assuming your image paths are correct. I might try hard-coding an image tag just to see that you have the correct path)

  1. Now that we have an image up, we want to be able to move from one to another. In our
   )


We add arrows. (I'm adding arrows from fontawesome inside of div tags.)

<div id="arrow-left" onClick={arrowLeftClick}><i className="fas fa-arrow-alt-circle-left"></i></div>
<div id="arrow-right" onClick={arrowRightClick}><i className="fas fa-arrow-alt-circle-right"></i></div>
  1. If you noticed, there's on onClick that will run functions (arrowLeftClick, arrowRightClick), let's create those. Here's both.
    const arrowRightClick = () => {
        currentPosition !== slides.length -1 ? // Check index length
        setCurrentPosition(currentPosition + 1) : setCurrentPosition(currentPosition = 0);
        currentSlide = slides[currentPosition];
    }

This is actually a ternary operator.
We are asking for a boolean condition
I've been taught put the more complex stuff first because it's less likely to hit.
We are starting out at 0 as our index, but we have to make up for after we get past the last image.
If the current position is not at the last image,

currentPosition !== slides.length -1

If that's true (not at the last image, img3.jpg in this case)

?

increase our index by 1, we're also doing this by running our setCurrentPosition we set earlier.

setCurrentPosition(currentPosition + 1)

If the case is false, (Is at the last image, img3.jpg)

:

go back to the first image, or the 0 index.

setCurrentPosition(currentPosition = 0);

Now update the slide with the following:

currentSlide = slides[currentPosition];

Here is the left click below, which really does the same thing, conditionals are just slightly different.

    const arrowLeftClick = () => {
        currentPosition !== 0 ? // Check index length
        setCurrentPosition(currentPosition - 1) : setCurrentPosition(currentPosition = slides.length - 1);
        currentSlide = slides[currentPosition];
    }

This doesn't have the CSS attached, but I think you can change it to however you would like.
Here's the full code:

import React, { useState } from 'react';

const Carousel = () => {

    const [slides] = useState([
        {
            source: "../images/img1.jpg",
            title: "Half Moon Pier"
        },
        {
            source: "../images/img2.jpg",
            title: "Port Washington Rocks"
        },
        {
            source: "../images/img3.jpg",
            title: "Abandoned Rail"
        }
    ]);

    // SET CAROUSEL DEFAULTS
    let [currentPosition, setCurrentPosition] = useState(0); // Initial slide index value
    let currentSlide = slides[currentPosition]; // variable index value we can reference later

    const arrowRightClick = () => {
        currentPosition !== slides.length -1 ? // Check index length
        setCurrentPosition(currentPosition + 1) : setCurrentPosition(currentPosition = 0);
        currentSlide = slides[currentPosition];
    }

    const arrowLeftClick = () => {
        currentPosition !== 0 ? // Check index length
        setCurrentPosition(currentPosition - 1) : setCurrentPosition(currentPosition = slides.length - 1);
        currentSlide = slides[currentPosition];
    }

    return (
        <div className="carousel-block">
            <div className="flex-container">
                <div id="slider">
                    <div className="slide">
                        <img src={currentSlide.source} alt={currentSlide.title} title={currentSlide.title} className="slider-img" />
                        <div className="arrows">
                            <div id="arrow-left" onClick={arrowLeftClick}><i className="fas fa-arrow-alt-circle-left"></i></div>
                            <div id="arrow-right" onClick={arrowRightClick}><i className="fas fa-arrow-alt-circle-right"></i></div>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    )
}

export default Carousel;