Next.js Discord

Discord Forum

Update state doesn't work in hook

Unanswered
Barbado da Terceira posted this in #help-forum
Open in Discord
Barbado da TerceiraOP
Hello everyone,

I'm trying to implement a hook called useCarousel to have a carousel in an easy way without adding too much logic/animations to my components.
The problem is that I've encountered many "bugs" with the state, because it doesn't update !

I use several useEffect and useCallback in my code, but I'm sure that I've implemented them properly so they should be working !

You can have a simple example with the handleDrag function, triggered from the onDrag parameter in my Draggable options.
Originally, my direction state is 0, I update the state with setDirection to "ok" just to see any difference, but nothing, still getting 0 in the console.log.

Anyone have an idea of what's causing this ?

1 Reply

Barbado da TerceiraOP
const useCarousel = (elementRef: React.RefObject<HTMLElement>, options: Draggable.Vars = {}) => {
  const [draggable, setDraggable] = useState<Draggable | null>(null)

  const [snapPoints, setSnapPoints] = useState<number[]>([])
  const [direction, setDirection] = useState<any>(0)

  const [slides, setSlides] = useState<Array<any>>([])
  const [currentSlide, setCurrentSlide] = useState<number>(0)

  useEffect(() => initCarousel(), [elementRef])

  useEffect(() => getSnapPoints(), [slides])

  useEffect(() => initDraggable(), [snapPoints])

  const handleSnapX = useCallback(() => {
    // ...
  }, [...])

  const handleDrag = useCallback(
    (d: any) => {
      setDirection('ok')
      console.log(direction)
    },
    [draggable, setDirection, direction]
  )

  const getSnapPoints = useCallback(() => {
    // ...
  }, [...])

  const draggableOptions: Draggable.Vars = useMemo(() => {
    return {
      ...options,
      type: 'x',
      bounds: {
        minX: snapPoints[slides.length - 1],
        maxX: 0,
      },
      maxDuration: 0.6,
      minDuration: 0.3,
      inertia: true,
      snap: {
        x: () => handleSnapX(),
      },
      onDrag: function () {
        handleDrag(this)
      },
    }
  }, [draggable, snapPoints, slides.length, options, handleSnapX, handleDrag])

  const initCarousel = () => {
    const haveElement = Boolean(elementRef.current)

    if (!haveElement) return

    setSlides(Array.from(elementRef.current!.children))

    getSnapPoints()

    window.addEventListener('resize', getSnapPoints)

    return () => {
      window.removeEventListener('resize', getSnapPoints)
    }
  }

  const initDraggable = () => {
    const haveSnapPoints = Boolean(snapPoints.length)
    const haveSlides = Boolean(slides.length)

    if (!haveSnapPoints || !haveSlides) return

    const d = Draggable.create(elementRef.current, draggableOptions)

    setDraggable(d[0])
  }

  return draggable
}

export default useCarousel