Negin Basiri
Negin Basiri

Reputation: 1375

Hide/Show React-slick arrows

I am using react-slick and I have my own customised arrows. This Slider is NOT an infinite loop and I would like to hide the arrows at the start and end of the loop. So basically at start PrevArrow should be hidden and at the end the NextArrow should be hidden. Which I am trying to set hidden class name depending on state changes. However the class name is not changing although the state is changing correctly. Do you know what's the problem with this code? and how to get it work?

Below is my setting for Slider and the component which renders Slider.

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Slider from 'react-slick';
import Arrow from '../slider/Arrow';


export default class CityCarousel extends Component {
    constructor(props) {
        super(props);

        this.state = {
            displayLeftArrow: true,
            displayRightArrow: true
        };


        this.slidesToShow = 5;
        this.sliderSetting = {
            dots: false,
            arrows: true,
            infinite: false,
            initialSlide: 0,
            slidesToShow: this.slidesToShow,
            slidesToScroll: 1,
            speed: 500,
            rows: 0,
            nextArrow: <Arrow
                    styleClassName={`city-carousel__right ${
                        this.state.displayRightArrow ? '' : 'city-carousel__right--hide'
                    }`}
                    direction="right"
                    clickHandler={this.clickHandler}
                />,
            prevArrow: <Arrow
                    styleClassName={`city-carousel__left ${
                        this.state.displayLeftArrow ? '' : 'city-carousel__left--hide'
                    }`}
                    direction="left"
                    clickHandler={this.clickHandler}
                />,
            afterChange: currentSlide => this.setArrowDisplay(currentSlide)
        };
    }

    clickHandler = direction => {
        if (direction === 'left') {
            this.slider.slickPrev();
        } else if (direction === 'right') {
            this.slider.slickNext();
        }
    };

    setArrowDisplay = currentSlide => {
        const { cityList } = this.props;
        const displayLeftArrow = currentSlide !== 0;
        const displayRightArrow = currentSlide !== cityList.length - this.slidesToShow;

        this.setState({ displayRightArrow, displayLeftArrow });
    };

    render() {
        const { cityList, tours } = this.props;
        return (
            <div>
                <div className="city-selection">
                    <Slider
                        ref={c => this.slider = c }
                        {...this.sliderSetting}
                    >
                        {cityList.length > 0 ? this.renderCityList() : null}
                    </Slider>
                </div>
            </div>
        );
    }
}

Here is also code for Arrow component

import React from 'react';
import PropTypes from 'prop-types';

const Arrow = ({ styleClassName, direction, clickHandler }) => {

    return(
    <div
        className={`slick-arrow--${direction} slider-arrow--${direction} ${styleClassName}`}
        onClick={e => clickHandler(direction)}
    />
)};

Arrow.propTypes = {
    styleClassName: PropTypes.string,
    direction: PropTypes.string,
    clickHandler: PropTypes.func
};

export default Arrow;

Upvotes: 6

Views: 11068

Answers (5)

Abdul.Moqueet
Abdul.Moqueet

Reputation: 1067

In 2022, we have boolean arrows, just declare it false in settings.

 const settings = {
        ...,
        arrows: false,
    };

Upvotes: 3

Jack Wuerfel
Jack Wuerfel

Reputation: 21

Pass the current slide prop to the component and do a check for the slide you want to trigger hiding the arrow:

function SamplePrevArrow(props) {
    const { currentSlide, className, onClick } = props;
    if (currentSlide === 0) {
        return false;
    } else {
        return <div className={className} onClick={onClick} />;
    }
}

Upvotes: 2

Ashraful Islam
Ashraful Islam

Reputation: 1263

If you want the best manual controls over the arrow then use a custom arrow.

  1. Create it by using a simple Arrow component.
  2. Set the onClick handler of that component by using a ref in the main Slider component.

    const sliderRef = useRef<Slider>(null);
    
    <Slider {...settings} ref={sliderRef}>
    
  3. Use states to conditionally show or hide arrows.

I wrote a blog post which covers the workflow to achieve similar kind of functionalities you want. You can have a look there.

https://medium.com/@imasharaful/image-slider-with-react-slick-d54a049f043

Upvotes: 0

Emad Emami
Emad Emami

Reputation: 6639

It seems react-slick is not re-rendering <Arrow /> with new props, and it's always with first initialized props setting.

I think the solution is to get <Arrow /> out of slider like this:

    <div className="city-selection">
      <Arrow
        styleClassName={`city-carousel__right ${
          this.state.displayRightArrow ? '' : 'city-carousel__right--hide'
          }`}
        direction="right"
        clickHandler={this.clickHandler}
      />
      <Arrow
        styleClassName={`city-carousel__left ${
          this.state.displayLeftArrow ? '' : 'city-carousel__left--hide'
          }`}
        direction="left"
        clickHandler={this.clickHandler}
      />
      <Slider
        {/* list of items*/}
      </Slider>
    </div>

you can see how it's working in here

Upvotes: 2

Adeel Imran
Adeel Imran

Reputation: 13966

In your this.sliderSettings set nextArrow & prevArrow for your Arrow component do something like this

<Arrow 
  styleClassName={'YOUR_CLASSES_HERE'}
  direction="right" 
  clickHandler={this.clickHandler} 
  isHidden={this.state.isHidden} 
/>

Where this.state.isHidden is the state variable where you are trying toggle the arrows.

Then in your Arrow component do something like this.

 const Arrow = ({ styleClassName, direction, clickHandler, isHidden }) => {

   return (
    <div
     className={`slick-arrow--${direction} slider-arrow--${direction} 
                ${styleClassName}`}
     style={{ display: isHidden: 'none': 'block' }}
     onClick={e => clickHandler(direction)}
    />
   )
 };

Upvotes: 0

Related Questions