0

I have a rotating image gallery using react and CSS. It works except every time I click the button to rotate forward or backward it takes two clicks to start working correctly. For instance the first click does nothing and second click goes, or if are scrolling right then click the left button it goes right one more time, then subsequent clicks start going left.

I know this maybe because the state is updated but it hasn't rerendered yet but no matter what I try it doesn't change anything. I tried moving the set transform into a separate function. I tried making it a variable that the function then sets equal to the state of currentTransform. I can't seem to get it to stop needing two clicks. Any help would be appreciated.

React code

const Rotating = () => {

const [currentTransform, setCurrentTransform] = useState(`perspective(1000px) rotateY(0deg)`);
const [imageGroup, setImageGroup] = useState("imageSet1");
const [x, setX] = useState(0);
const numberOfPictures = 8;

const handlePreviousButton = () => {
    setX(x + 45);
    setCurrentTransform(`perspective(1000px) rotateY(${x}deg)`);
}

const handleNextButton = () => {
    setX(x - 45);
    setCurrentTransform(`perspective(1000px) rotateY(${x}deg)`);
}

const changeImageSet = (imageSet: string) => {
    setImageGroup(imageSet);
}

return (
    <div className="rotating-gallery-main-div-style">
        <div className="rotating-gallery-btn-container">
            <Button onClick={() => changeImageSet("imageSet1")} className="image-group-btn" variant="primary">
                Pictures
            </Button>
            <Button onClick={() => changeImageSet("imageSet2")} className="image-group-btn" variant="primary">
                Other Pictures
            </Button>
        </div>
        <div className="rotating-gallery-image-container" style={{transform: currentTransform} as React.CSSProperties}>
            {[...Array(numberOfPictures)].map((_, index) =>
                <span style={{ "--i": index } as React.CSSProperties} key={index}>
                    <img
                        src={`/images/${imageGroup}/${index}.jpg`}
                    />
                </span>
            )}
        </div>
        <div className="rotating-gallery-btn-container">
            <Button onClick={handlePreviousButton} className="rotating-gallery-prev-btn rotating-gallery-btn" variant="primary">Previous</Button>
            <Button onClick={handleNextButton} className="rotating-gallery-next-btn rotating-gallery-btn" variant="primary">Next</Button>
        </div>
    </div>
)

}

CSS

.rotating-gallery-main-div-style {
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  height: 100vh;
  background: black;
  overflow: hidden;
}
.rotating-gallery-image-container {
  position: relative;
  width: 250px;
  height: 250px;
  transform-style: preserve-3d;
  transform: perspective(1000px) rotateY(0deg);
  transition: transform 0.7s;
}
.rotating-gallery-image-container span {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  transform: rotateY(calc(var(--i) * 45deg)) translateZ(400px);
}
.rotating-gallery-image-container span img {
  position: absolute;
  left: 0;
  top: -30px;
  width: 100%;
  max-height: 225px;
}
.rotating-gallery-btn-container {
  position: relative;
  width: 80%;
}
.rotating-gallery-btn {
  position: absolute;
  bottom: -80px;
  border: none;
  padding: 10px 20px;
  border-radius: 5px;
}
.image-group-btn {
  position: relative;
  top: -180px;
  margin-left: 10px;
}
.rotating-gallery-prev-btn {
  left: 20%;
}
.rotating-gallery-next-btn {
  right: 20%;
}
.rotating-gallery-btn:hover {
  filter: brightness(1.5);
}
1
  • 1
    Don't have time to experiment right now but my suspicion is that the problem is to do with having multiple state setters in your click handler. Once the first one is fired you may be triggering a re-render, and the behaviour of the second one might be unpredictable. A good solution is to store your state as an object and to update multiple fields at once to make sure the update is properly atomic. Commented Feb 21, 2024 at 20:50

1 Answer 1

1

In react setState is async, so when you call setX(newVal), your x is not updated yet. Try this

const handlePreviousButton = () => {
    const newXValue = x + 45
    setX(newXValue);
    setCurrentTransform(`perspective(1000px) rotateY(${newXValue}deg)`);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I tried so many solutions and this was it. Good to learn about the async nature of setState as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.