<commit_before>import React, {
  useRef,
  useState,
  useEffect,
  useCallback,
  forwardRef,
  useImperativeHandle,
} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import cx from 'clsx';

const useStyles = makeStyles(() => ({
  slider: {
    display: 'flex',
    position: 'relative',
    scrollSnapType: 'x mandatory',
    overflowX: 'scroll',
    width: '100%',
    scrollbarWidth: 'none',
    MsOverflowStyle: 'none',

    '&::-webkit-scrollbar': {
      display: 'none',
    },
  },
  slideWrapper: {
    scrollSnapAlign: 'start',
    flexShrink: 0,
    width: '100%',
  },
}));

const Slider = (
  {
    className,
    children,
    autoplay = false,
    interval = 3000,
    slideWrapperClassName,
    initIndex = 0,
    onSlideChange = () => {},
  },
  ref
) => {
  const classes = useStyles();

  const [activeSlide, setActiveSlide] = useState(initIndex);
  const [timeoutId, setTimeoutId] = useState(null);

  const sliderRef = useRef(null);

  const slides = React.Children.toArray(children);
  const slidesAmount = slides.length;

  const slideTo = useCallback(
    (index, smooth = true) => {
      const slider = sliderRef.current;

      if (slider) {
        slider.scrollTo({
          left: slider.scrollWidth * (index / slidesAmount),
          behavior: smooth ? 'smooth' : 'auto',
        });
      }
    },
    [slidesAmount]
  );

  const autoplayNext = useCallback(() => {
    if (timeoutId) {
      clearTimeout(timeoutId);
      setTimeoutId(null);
    }

    const id = setTimeout(() => {
      const nextSlide = activeSlide === slidesAmount - 1 ? 0 : activeSlide + 1;
      slideTo(nextSlide);
    }, interval);

    setTimeoutId(id);
  }, [slidesAmount, activeSlide, interval, timeoutId, slideTo]);

  useImperativeHandle(
    ref,
    () => ({
      activeIndex: activeSlide,
      slideTo,
      reset: () => {
        slideTo(initIndex);

        if (autoplay) {
          autoplayNext();
        }
      },
    }),
    [activeSlide, slideTo, initIndex, autoplay, autoplayNext]
  );

  useEffect(() => {
    const slider = sliderRef.current;

    slideTo(initIndex, false);

    const onScroll = () => {
      const slider = sliderRef.current;

      if (slider) {
        const index = Math.round(
          (slider.scrollLeft / slider.scrollWidth) * slidesAmount
        );

        setActiveSlide(index);
      }
    };

    if (slider) {
      slider.addEventListener('scroll', onScroll);
    }

    return () => {
      if (slider) {
        slider.removeEventListener('scroll', onScroll);
      }
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sliderRef, slidesAmount]);

  useEffect(() => {
    if (autoplay) {
      autoplayNext();
    } else {
      clearTimeout(timeoutId);
    }

    return () => {
      if (timeoutId) {
        clearTimeout(timeoutId);
      }
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoplay, activeSlide, interval]);

  useEffect(() => {
    onSlideChange(activeSlide);
  }, [activeSlide, onSlideChange]);
<commit_msg>[Tutorial] store slider's timeoutId with ref instead of state<commit_after>import React, {
  useRef,
  useState,
  useEffect,
  useCallback,
  forwardRef,
  useImperativeHandle,
} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import cx from 'clsx';

const useStyles = makeStyles(() => ({
  slider: {
    display: 'flex',
    position: 'relative',
    scrollSnapType: 'x mandatory',
    overflowX: 'scroll',
    width: '100%',
    scrollbarWidth: 'none',
    MsOverflowStyle: 'none',

    '&::-webkit-scrollbar': {
      display: 'none',
    },
  },
  slideWrapper: {
    scrollSnapAlign: 'start',
    flexShrink: 0,
    width: '100%',
  },
}));

const Slider = (
  {
    className,
    children,
    autoplay = false,
    interval = 3000,
    slideWrapperClassName,
    initIndex = 0,
    onSlideChange = () => {},
  },
  ref
) => {
  const classes = useStyles();

  const [activeSlide, setActiveSlide] = useState(initIndex);
  const timeoutId = useRef(null);
  const sliderRef = useRef(null);

  const slides = React.Children.toArray(children);
  const slidesAmount = slides.length;

  const slideTo = useCallback(
    (index, smooth = true) => {
      const slider = sliderRef.current;

      if (slider) {
        slider.scrollTo({
          left: slider.scrollWidth * (index / slidesAmount),
          behavior: smooth ? 'smooth' : 'auto',
        });
      }
    },
    [slidesAmount]
  );

  const autoplayNext = useCallback(() => {
    if (timeoutId.current) {
      clearTimeout(timeoutId.current);
      timeoutId.current = null;
    }

    const id = setTimeout(() => {
      const nextSlide = activeSlide === slidesAmount - 1 ? 0 : activeSlide + 1;
      slideTo(nextSlide);
    }, interval);

    timeoutId.current = id;
  }, [slidesAmount, activeSlide, interval, timeoutId, slideTo]);

  useImperativeHandle(
    ref,
    () => ({
      activeIndex: activeSlide,
      slideTo,
      reset: () => {
        slideTo(initIndex);

        if (autoplay) {
          autoplayNext();
        }
      },
    }),
    [activeSlide, slideTo, initIndex, autoplay, autoplayNext]
  );

  useEffect(() => {
    const slider = sliderRef.current;

    slideTo(initIndex, false);

    const onScroll = () => {
      const slider = sliderRef.current;

      if (slider) {
        const index = Math.round(
          (slider.scrollLeft / slider.scrollWidth) * slidesAmount
        );

        setActiveSlide(index);
      }
    };

    if (slider) {
      slider.addEventListener('scroll', onScroll);
    }

    return () => {
      if (slider) {
        slider.removeEventListener('scroll', onScroll);
      }
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sliderRef, slidesAmount]);

  useEffect(() => {
    if (autoplay) {
      autoplayNext();
    } else {
      clearTimeout(timeoutId.current);
    }

    return () => {
      if (timeoutId.current) {
        clearTimeout(timeoutId.current);
      }
    };

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoplay, activeSlide, interval]);

  useEffect(() => {
    onSlideChange(activeSlide);
  }, [activeSlide, onSlideChange]);

{'fraction_non_alphanumeric': 0.14400643604183427, 'fraction_numerical': 0.004827031375703942, 'mean_word_length': 2.515837104072398, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1507409', 'n_tokens_mistral': 2064, 'n_tokens_neox': 1980, 'n_words': 397}