React Hooks Example: Timer

Simple React Hooks example. A timer that pauses when you hold the mouse button. Creates and uses a custom Hook.

HTML

<div id="app"></div>

SCSS

.carousel-wrapper {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
  margin-bottom: 0.5rem;
  height: 8rem;

  .arrow {
    height: fit-content;
    align-self: center;
  }

  .items-wrapper {
    display: grid;
    /* grid-template-columns: repeat(4, 2.5rem); */
    grid-template-areas: "a b c d" "e f g h";
    gap: 1rem;
  margin: auto 0;

    .item {
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      box-shadow: 0px 4px 4px rgba(46, 37, 37, 0.15), 0px 0px 10px 1px rgba(203, 205, 208, 0.3);
      border-radius: 4px;
      padding: 0.5rem;
      height: 2.5rem;
      transition: opacity 0.8s calc(var(--delay) + var(--delayOffset, 0s));
      
      &.is-hidden {
        /* visibility: hidden; */
        opacity: 0;
        --delayOffset: -0.8s;
      }
      
      &.pos0 { grid-area: a; --delay: 0.8s; }
      &.pos1 { grid-area: b; --delay: 0.9s; }
      &.pos2 { grid-area: c; --delay: 1.0s; }
      &.pos3 { grid-area: d; --delay: 1.1s; }
      &.pos4 { grid-area: e; --delay: 1.2s; }
      &.pos5 { grid-area: f; --delay: 1.3s; }
      &.pos6 { grid-area: g; --delay: 1.4s; }
      &.pos7 { grid-area: h; --delay: 1.5s; }
    }
  }
}

React

const items = [
  { id: 1 },
  { id: 2 },
  { id: 3 },
  { id: 4 },
  { id: 5 },
  { id: 6 },
  { id: 7 },
  { id: 8 },
  { id: 9 },
  { id: 10 },
  { id: 11 },
  { id: 12 },
  { id: 13 },
  { id: 14 },
  { id: 15 },
  { id: 16 },
  { id: 17 },
  { id: 18 },
  { id: 19 },
  { id: 20 },
  { id: 21 },
  { id: 22 },
  { id: 23 },
  { id: 24 },
];

function isDisplayedItem(index, displayedSlice) {
  return index >= displayedSlice.start && index < displayedSlice.end;
}

const Carousel = () => {
  const [displayedSlice, setDisplayedSlice] = React.useState({
    start: 0,
    end: 8,
  });
  
  const itemsPerSlide = 8;

  return (
    <div className="carousel-wrapper">
      <button
        className="arrow"
        disabled={displayedSlice.start === 0}
        onClick={() =>
          setDisplayedSlice((currentSlice) => ({
            start: currentSlice.start - itemsPerSlide,
            end: currentSlice.end - itemsPerSlide,
          }))
        }
      >
        -
      </button>
      <div className="items-wrapper">
        {items.map((item, index) => (
          <div
            key={index}
            className={`item
            	${!isDisplayedItem(index, displayedSlice) ? "is-hidden" : ""}
            	pos${index % itemsPerSlide}
            `}
          >
            {index}
          </div>
        ))}
      </div>
      <button
        className="arrow"
                disabled={displayedSlice.end > items.length - 1}
        onClick={() =>
          setDisplayedSlice((currentSlice) => ({
            start: currentSlice.start + itemsPerSlide,
            end: currentSlice.end + itemsPerSlide,
          }))
        }
      >
        +
      </button>
    </div>
  );
};

ReactDOM.render(<Carousel />, document.querySelector("#app"));