3

I have a component that uses two sliders in combination(a total of 4). One combination is for horizontal carousel and another for vertical. This decision is based upon the screen size.

When it is rendered in smaller devices it is working fine but on larger screens, it renders but as soon as I click on buttons for moving the slides it crashes and presents me with the following error.

enter image description here

I am using react-slick for the carousel.

Here's the component code:

class Carousel extends Component {
   constructor(props) {
    super(props);
    this.state = {
        imageSlider: null,
        contentSlider: null,
        isMobile: true
    };

    this.getHorizontalSlider = this.getHorizontalSlider.bind(this);
    this.getVerticalSlider = this.getVerticalSlider.bind(this);
}

componentDidMount() {

    const isMobile = window.screen.width > 768 ? false : true;

    this.setState({
        imageSlider: this.slider1,
        contentSlider: this.slider2,
        isMobile: isMobile
    });
}

getHorizontalSlider() {
    return (
        <div className={this.props.className}>
            <Slider
                asNavFor={this.state.contentSlider}
                ref={slider => (this.slider1 = slider)}
                className={styles.horizontalImageSlider}
                focusOnSelect={false}
                arrows={false}
                dots={true}
                autoplay={true}
                autoplaySpeed={7000}
            >
                {
                    data.map((item, index) => (
                        <div key={index}>
                            <img src={item.imageUrl} className={`${styles.carouselImage} img-fluid mx-auto`} alt="" />
                        </div>
                    ))
                }
            </Slider>
            <Slider
                asNavFor={this.state.imageSlider}
                ref={slider => (this.slider2 = slider)}
                focusOnSelect={false}
                arrows={false}
            >
                {
                    data.map((item, index, arr) => (
                        <div key={index} className='text-center text-secondary'>
                            <h2 className="text-primary fw-bold mb-4">{item.heading}</h2>
                            <p className='lead px-2'>{item.description}</p>
                        </div>
                    ))
                }
            </Slider>
        </div>
    )
}


getVerticalSlider() {
    return (
        <div className={`row ${this.props.className}`}>
            <div className="col-4">
                <Slider
                    asNavFor={this.state.contentSlider}
                    ref={slider => (this.slider1 = slider)}
                    vertical={true}
                    arrows={false}
                    slidesToScroll={1}
                    verticalSwiping={false}
                    focusOnSelect={false}
                    slidesToShow={1}
                >
                    {
                        data.map((item, index) => (
                            <div key={index}>
                                <img src={item.imageUrl} className={`${styles.carouselImage} img-fluid mx-auto`} alt="" />
                            </div>
                        ))
                    }
                </Slider>
            </div>

            <div className="col-8">
                <div className='d-flex justify-content-center align-items-center h-100'>
                    <Slider
                        className={styles.verticalContentSlider}
                        asNavFor={this.state.imageSlider}
                        ref={slider => (this.slider2 = slider)}
                        slidesToScroll={1}
                        slidesToShow={1}
                        swipeToSlide={true}
                        focusOnSelect={true}
                        vertical={true}
                        adaptiveHeight={true}
                        nextArrow={<CustomArrow />}
                        prevArrow={<CustomArrow />}
                    >
                        {
                            data.map((item, index, arr) => (
                                <div key={index}>
                                    {getSlideContent(item, index, arr)}
                                </div>
                            ))
                        }
                    </Slider>
                </div>
            </div>
        </div>
    )
}

render() {

    if (this.state.isMobile === true) {
        return this.getHorizontalSlider();
    }

    return this.getVerticalSlider();
}

}

I know it's not the best code out, but I want to make this work first and then refactor it. Thanks for reading this, much appreciated.

Whyashh
  • 93
  • 9
  • Seems to be related to conflicting `ref`s as the issue only happens when a different `` is rendered after mounting. – juliomalves Jan 23 '21 at 14:56
  • Seemed like that.. so I ended up extracting them into individual components (VerticaSlider & HorizontalSlider). This seemed to fix this issue on my end. However, I am not sure whether that should be accepted as an answer. – Whyashh Jan 23 '21 at 17:21

1 Answers1

1

It looks like your setState() will only be executed once, after the component mounts with the mobile defaults. That means that when your component re-renders to show the vertical sliders, imageSlider and contentSlider still point to the mobile, horizontal sliders. This would cause react-slick to throw an error when trying to resolve your asNavFor settings.

One way to avoid this might be to set your default mobile state in the constructor instead of componentDidMount, so that only one set of components (horizontal or vertical) will ever be rendered.

   constructor(props) {
     super(props);

     this.state = {
       imageSlider: null,
       contentSlider: null,
       isMobile: window.screen.width <= 768
     };

     ...

   }
Ed Lucas
  • 5,955
  • 4
  • 30
  • 42
  • 1
    Yes. Thank You. Just verified. It works. I had this sort of an intuition that this might be the case. However, I took the easy way out and created individual components for both of them. – Whyashh Jan 27 '21 at 16:42