Search code examples
javascriptreactjscarouselswipedrag

How to drag carousel on swipe in React


I'm a junior dev and am struggling with an issue where there is a carousel with about 10 cards on top of the page. All cards do not fit at once on the screen, so there are 2 arrows in the corner to scroll them (arrow left and arrow right). When you click arrow right, the cards scroll to the end and when you click arrow left they move backwards from right to left.

How can I make it that when you click mouse down and hold the images and drag them they move left or right? I need to make them move not only with arrow clicks but with mouse drag also... Do i need to use some library (i found react-hammerjs, but didn't find any good docs/examples how to use it)? Thank you in advance for your help

Here's some code to reference:

export const CardsBlock = () => {
  const scrollContainer = useRef(null)
  const [scrolled, setScrolled] = useState(false)
  const dispatch = useDispatch()

  useEffect(() => {
    const resizeListener = (e) => {
      if (e.target.outerWidth <= sizes.mobile) {
        setScrolled(null)
      } else {
        setScrolled(false)
      }
    }
    window.addEventListener('resize', resizeListener)
    return () => {
      window.removeEventListener('resize', resizeListener)
    }
  }, [])


  useEffect(() => {
    if (scrolled) {
      scrollTo(scrollContainer.current, scrollContainer.current.offsetWidth)
    } else {
      scrollTo(scrollContainer.current, 0)
    }
  }, [scrolled])

  return (
    <Well>
      <Container>
        <Wrapper padding={'0 0 16px'} justify={'space-between'} align={'center'}>
          <TitleText width={'auto'}>{translator('specilization.title', true)}</TitleText>
          <ArrowsContainer>
            <Icon
              onClick={() => setScrolled(false)}
              cursor={'pointer'}
              type={'arrow_left'}
              color={scrolled ? 'black4' : 'black1'}
            />
            <Icon
              onClick={() => setScrolled(true)}
              cursor={'pointer'}
              type={'arrow_right'}
              color={scrolled ? 'black1' : 'black4'}
            />
          </ArrowsContainer>
        </Wrapper>
        <SpecializationsInnerContainer ref={scrollContainer}>
          {specializations.map((specialization) =>
            <SpecializationCard
              key={specialization.id}
              image={specialization.image}
              title={specialization.title}
              color={'black1'}
              borderColor={'transparent'}
              onClick={() => handleOnClick(specialization.id)}
            />
          )}
          <SpecializationCard borderColor={'black15'} image={'image.png'} isAll onClick={openSpecializationFilter} title={translator('specilization.all', true)} color={'transparent'}/>
        </SpecializationsInnerContainer>
      </Container>
    </Well>
  )
}

Solution

  • During more research found an answer in 'react-swipeable' npm module https://www.npmjs.com/package/react-swipeable

    As the arrow icons onclick logic is already defined here, added the same logic to react swipeable component:

           <Swipeable onSwipedLeft={() => setScrolled(true)} onSwipedRight={() => setScrolled(false)} trackMouse={true}>
            <SpecializationsInnerContainer ref={scrollContainer}>
              {specializations.map((specialization) =>
                <SpecializationCard
                  key={specialization.id}
                  image={specialization.image}
                  title={specialization.title}
                  color={'black1'}
                  borderColor={'transparent'}
                  onClick={() => handleOnClick(specialization.id)}
                />
              )}
              <SpecializationCard borderColor={'black15'} image={'image.png'} isAll onClick={openSpecializationFilter} title={translator('specilization.all', true)} color={'transparent'}/>
            </SpecializationsInnerContainer>
           </Swipeable>