javascriptreactjscarouselinfinite-carousel

React JS Infinite Carousel


I'm building a portfolio app in React JS and one of my pages is an About Me page. I stumbled upon a youtube video that builds an infinite carousel using vanilla JavaScript, and during my initial testing it worked. However, when I navigate away from my 'About Me' page and return, it explodes with a "TypeError: Cannot read property 'style' of null" within my About Me component "stepNext; src/components/about-me/AboutMe.js:34".

import React from "react";
import "./AboutMe.css"
import { Button, 
    Fade,
    Grow,
    Typography } from '@material-ui/core'
import { ArrowBackIos, ArrowForwardIos } from "@material-ui/icons";
import { Background, Adventures, Hobbies } from "./about-me-components/index";

export const AboutMe = () => {
    const slider = document.querySelector('.slider-about-me')
    const carousel = document.querySelector('.carousel-about-me')

    let direction = 1

    const stepPrevious = () => {
        if (direction === 1) {
            slider.appendChild(slider.firstElementChild)
        }
        direction = -1
        console.log("Previous", direction)
        carousel.style.justifyContent = 'flex-end'
        slider.style.transform = 'translate(33%)'
    }

    const stepNext = () => {
        if (direction === -1) {
            slider.prepend(slider.lastElementChild)
        }
        direction = 1
        console.log("Next", direction)
        carousel.style.justifyContent = 'flex-start'
        slider.style.transform = 'translate(-33%)'
    }

    const sliderAppend = () => {
        if (direction === 1) { 
            slider.appendChild(slider.firstElementChild)
        } else if (direction === -1) { 
            slider.prepend(slider.lastElementChild)
        }
        slider.style.transition = 'none'
        slider.style.transform = 'translate(0)'
        setTimeout(() => {slider.style.transition = 'all 0.5s'})
    }

    return (
        <>
            <Fade
                in={true}
                timeout={1500}
            >
                <div
                    id='about-me-container'
                >
                    <div className="controls">
                        <div
                            className='arrow-span-about-me arrow-left-about-me'
                        >
                            <Button
                                className='button-about-me arrow-about-me'
                                variant='contained'
                                onClick={stepPrevious}
                            >
                                <ArrowBackIos 
                                    className="arrow-back-about-me"
                                />
                            </Button>

                        </div>

                        <div
                            className='arrow-span-about-me arrow-right-about-me'
                        >
                            <Button
                                className='button-about-me arrow-about-me'
                                variant='contained'
                                onClick={stepNext}
                            >
                                <ArrowForwardIos 
                                    className="arrow-forward-about-me"
                                />
                            </Button>
                        </div>
                    </div>

                <div
                    id="about-me-carousel-container"
                >
                    <div
                        className='carousel-about-me'
                    >
                        <div
                            className='slider-about-me'
                            onTransitionEnd={sliderAppend}
                        >
                            <section className='text-white'><Background /></section>
                            <section className='text-white'><Adventures /></section>
                            <section className='text-white'><Hobbies /></section>
                        </div>
                        
                    </div>
                </div>
                </div>

            </Fade>
        </>
    )
}

The only reason I chose this route is because I haven't been able to find a half decent infinite carousel module with easy customization abilities. As much as I would prefer for this to work, I'm open to suggestions and/or solutions. Much appreciated!


Solution

  • I would suggest using useRef instead of document.querySelector

    document.querySelector happens outside of that lifecycle, making what it returns unreliable, while refs happen within it. (Though doesn’t get reset because of a lifecycle event like a re-render.) This ensures the object returned by the ref is an accurate representation of the current state of the virtual DOM.

    I think this is the reason why you are encountering the said error when you go away and back from the About Page.

    Here's an example: https://codesandbox.io/s/objective-fast-vhc27?file=/src/modalAndButton.jsx:531-648