akiran / react-slick

React carousel component
http://react-slick.neostack.com/
MIT License
11.76k stars 2.11k forks source link

slickGoTo inside useEffect doesn't work. #2037

Open adammo94 opened 3 years ago

adammo94 commented 3 years ago

so I have following problem, I want my slider to go back to slide 6 after if anyone would try to swipe further. However it doesn't work. UseEffect is being triggered, IF condition is being met, but the function won't run. If I put the same function call inside JSX like first snippet below it works how it should:

<button onClick={() => sliderRef.current.slickGoTo(5)} >go to slide 6</button>

This is my code:

const [activeSlide, setActiveSlide] = useState(0)
const sliderRef = useRef(null)
  const settings = {
    variableWidth: true,
    speed: 500,
    pauseOnHover: false,
    swipeToSlide: false,
    focusOnSelect: false,
    infinite: false,
    slidesToScroll: 1,
    arrows: false,
    beforeChange: (current, next) => setActiveSlide(next)
  }
useEffect(() => {
    if (window.innerWidth > 1100 && activeSlide > 5) {
      sliderRef.current.slickGoTo(5)
    }
  }, [activeSlide])
  <Slider {...settings} className={sliderClass} ref={sliderRef}>
devdpontes commented 3 years ago

@adammo94 If you do sliderRef.current.slider.slickGoTo(5), it should work. Apparently the ref is given the whole Carousel instance, not just the slider.

faridsaud commented 3 years ago

Same issue here

adammo94 commented 3 years ago

@adammo94 If you do sliderRef.current.slider.slickGoTo(5), it should work. Apparently the ref is given the whole Carousel instance, not just the slider.

This gives me undefined

clearyandzap commented 3 years ago

@adammo94 what happens if you console.log sliderRef.current inside the effect?

What if you try:

useEffect(() => { if (window.innerWidth > 1100 && activeSlide > 5) { sliderRef.current.slickGoTo(5) } }, [activeSlide, sliderRef.current])

McSam94 commented 3 years ago

any update on this issue? having the same problem.

x1aodingdang commented 3 years ago

The following keeps me working normally

 const sliderRef = useRef(null);

 <Slider  ref={sliderRef} />

 sliderRef.current?.slickNext?.()
MonstraG commented 2 years ago

@adammo94

You've forgot to put in sliderRef.current into dependency array of the useEffect:

useEffect(() => {
    if (window.innerWidth > 1100 && activeSlide > 5) {
      sliderRef.current.slickGoTo(5)
    }
  }, [activeSlide, sliderRef.current])

scratch that, refs do not affect rendering, so this will not do anything

diego06884 commented 2 years ago

It looks like sliderRef.current returns the DOM element instead of the slick instance. Any updates on this?

alex254 commented 2 years ago

same problem here, tried above ideas but dont work. Any idea for a workaround?

alex254 commented 2 years ago

cant figure out why its not working, please help

pbl6asoad commented 2 years ago

@alex254 Have you resolved this issue?

upd. check this thread, it helped me #2264

alex254 commented 2 years ago

@pbl6asoad nope, tried the waitForAnimate, issue persists.

here is my code:

function ProductImage({
  images, product, influencer, selectedVariant, hideDescription = false,
}: ProductImageProps) {
  const [, setState] = useState(false);
  const [index, setIndex] = useState(0);
  const sliderImageRef = useRef(null);
  const sliderNavRef = useRef(null);

  const { t } = useTranslation();

  useEffect(() => {
    setState(true);
    // on a new variant selection we want the image to slide to the variant image. However there is a bug in slickGoTo which is not working.
    // if (selectedVariant && sliderImageRef) {
    //   sliderImageRef.current.slickGoTo(1);
    // }
  }, [selectedVariant, sliderImageRef]);

  const currentProduct = Array.isArray(product) ? product[index] : product;

  const CarouselComponent = (
    <>
      <SliderContainer>
        <NavigationSlider
          asNavFor={sliderImageRef && sliderImageRef.current}
          // eslint-disable-next-line no-return-assign
          ref={sliderNavRef}
          slidesToShow={3}
          slidesToScroll={1}
          focusOnSelect
          vertical
          verticalSwiping
          arrows={false}
        >
          {
            images?.map((image) => <NavigationImage key={image.src} src={image.src} />)
          }
        </NavigationSlider>
        <ImageSlider
          asNavFor={sliderNavRef && sliderNavRef.current}
          // eslint-disable-next-line no-return-assign
          ref={sliderImageRef}
          slidesToShow={1}
          slidesToScroll={1}
          swipeToSlide
          dots
          arrows={false}
          afterChange={setIndex}
          appendDots={(dots) => (
            <DotsContainer>
              <ul> {dots} </ul>
              <TabletAvatar product={currentProduct} influencer={influencer} />
            </DotsContainer>
          )}
        >
          {
            images?.map((image) => (
              <InnerImageZoom
                key={image.src}
                className="customImageZoom"
                src={image.src}
                imgAttributes={{
                  src: image.src,
                  title: image.alt,
                  alt: image.alt,
                }}
                zoomScale={1.5}
                fullscreenOnMobile
              />
            ))
          }
        </ImageSlider>
      </SliderContainer>
    </>
  );

  return (
    <div
      data-cy="carousel"
    >{CarouselComponent}
    </div>
  );
}

export default ProductImage;

and an impression:

image

any suggestion on how to solve this?

aniruddhashevle commented 1 year ago

@akiran @devdpontes : Any updates on this? For me its working on 2nd click. But not the first!

devdpontes commented 1 year ago

@akiran @devdpontes : Any updates on this? For me its working on 2nd click. But not the first!

@aniruddhashevle Sorry for the late reply but we've decided to migrate to a smaller alternative, so unfortunately I can't give more input on this at the moment. I can try to checkout the previous code at some point and see if I can help figure out what could be happening.

ankumar3 commented 1 year ago

Any updates or workarounds on this issue? @akiran @devdpontes

jaredparker commented 1 year ago

@ankumar3 Not sure on the cause. But for me, I have found that useRef doesn't work and I needed to create a state reference. So, instead of:

const sliderRef = useRef(null);
...
<Slider ref={ sliderRef }>

I had to use the following:

const [ slickSlider, setSlickSlider ] = useState(null);
...
<Slider ref={ slider => setSlickSlider( slider ) }>

I found this out from this example.

ankumar3 commented 1 year ago

Awesome, thanks for sharing @jaredparker

In my case, I needed to open a particular slide on Carousel Init only so I used the Slider onInit like this: const onInit = () => {setInitState(true)} ... <Slider ref={ sliderRef } onInit={onInit}>

And then used the useEffect: useEffect(() => { sliderRef.current?.slickGoTo(index) }, [initState])

boshka0 commented 1 year ago

What helped me: const sliderRef = useRef(null); useEffect(() => sliderRef.current?.innerSlider?.changeSlide({ message: 'index', index: 0 }, true), [])

Got that from reading react-slick code

TimaRadjabov commented 10 months ago

Hi everyone! Just add second argument. I think it is animation bag, and need to turn off it. For me worked sliderRef.current.slickGoTo(selectedIndex, true) I found this out from API https://react-slick.neostack.com/docs/api

VMLuca commented 7 months ago

Hey guys, any updates on this issue? None of the solutions worked for me. Is it planned to be fixed?