1

I am currently working on image carousel and there is some issue with image loading. My stack is: Next.js + embla. When I am trying to scroll carousel first 2 images loads pretty fast, but third is very slow for loading. Here is my code:

/* eslint-disable jsx-a11y/control-has-associated-label */
import React, {
  ReactElement,
  useCallback,
  useEffect,
  useState,
  MouseEventHandler,
} from 'react';
import { CarouselProps } from 'interfaces/components';
import Image from 'next/image';
import useEmblaCarousel from 'embla-carousel-react';
import clsx from 'clsx';
import styles from './carousel.module.scss';

const Carousel = (props: CarouselProps): ReactElement => {
  const { images, hasShadow } = props;

  const [emblaRef, embla] = useEmblaCarousel({ loop: true });
  const [selectedIndex, setSelectedIndex] = useState(0);

  const scrollPrev = useCallback(
    (e) => {
      e.preventDefault();
      if (embla) embla.scrollPrev();
    },
    [embla]
  );

  const scrollNext = useCallback(
    (e) => {
      e.preventDefault();
      if (embla) embla.scrollNext();
    },
    [embla]
  );

  const scrollTo = useCallback(
    (e, index) => {
      e.preventDefault();
      if (embla) embla.scrollTo(index);
    },
    [embla]
  );

  const onSelect = useCallback(() => {
    if (!embla) return;
    setSelectedIndex(embla.selectedScrollSnap());
  }, [embla, setSelectedIndex]);

  useEffect(() => {
    if (!embla) return;
    onSelect();
    embla.on('select', onSelect);
  }, [embla, onSelect]);

  const imagesOrPlaceholder =
    images == null || images.length === 0
      ? ['/images/placeholder.jpg']
      : images;

  const NextButton = ({ onClick }: { onClick: MouseEventHandler }) => (
    <button
      className={[styles.arrow, styles.next].join(' ')}
      onClick={onClick}
      type="button"
    >
      <svg
        xmlns="http://www.w3.org/2000/svg"
        height="48px"
        viewBox="0 0 24 24"
        width="48px"
        fill="#FFFFFF"
      >
        <path d="M9.29 15.88L13.17 12 9.29 8.12c-.39-.39-.39-1.02 0-1.41.39-.39 1.02-.39 1.41 0l4.59 4.59c.39.39.39 1.02 0 1.41L10.7 17.3c-.39.39-1.02.39-1.41 0-.38-.39-.39-1.03 0-1.42z" />
      </svg>
    </button>
  );

  const PrevButton = ({ onClick }: { onClick: MouseEventHandler }) => (
    <button
      className={[styles.arrow, styles.prev].join(' ')}
      onClick={onClick}
      type="button"
    >
      <svg
        xmlns="http://www.w3.org/2000/svg"
        height="48px"
        viewBox="0 0 24 24"
        width="48px"
        fill="#FFFFFF"
      >
        <path d="M14.71 15.88L10.83 12l3.88-3.88c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L8.71 11.3c-.39.39-.39 1.02 0 1.41l4.59 4.59c.39.39 1.02.39 1.41 0 .38-.39.39-1.03 0-1.42z" />
      </svg>
    </button>
  );

  return (
    <div className={styles.embla} style={{ boxShadow: `${hasShadow ? "0px 4px 4px #AEA6A5" : ''}` }}>
      <div className={styles.embla__viewport} ref={emblaRef}>
        <div className={styles.embla__container}>
          {imagesOrPlaceholder.map((img, idx) => (
            <div className={styles.embla__slide} key={img}>
              <div className={styles.embla__slide__inner}>
                <Image
                  src={img}
                  layout="responsive"
                  width="100%"
                  height="125%"
                  objectFit="cover"
                  quality={100}
                  className={styles.featuredTileImage}
                />
              </div>
            </div>
          ))}
        </div>
      </div>
      {imagesOrPlaceholder.length > 1 && (
        <>
          <PrevButton onClick={scrollPrev} />
          <NextButton onClick={scrollNext} />
        </>
      )}
      <div className={styles.dots}>
        {imagesOrPlaceholder.length > 1 && imagesOrPlaceholder.map((_value, index) => (
          <div className={styles.dotContainer} key={index}>
            <div className={styles.dotAspect} />
            <div
              role="button"
              onClick={(e) => scrollTo(e, index)}
              onKeyDown={(e) => scrollTo(e, index)}
              tabIndex={0}
              className={clsx(
                styles.dot,
                selectedIndex === index && styles.active
              )}
            />
          </div>
        ))}
      </div>
    </div>
  );
};

export default Carousel;

And this is my carousel

https://i.sstatic.net/SwaBB.png

Maybe this is some issue with Image component from Next.js?

1 Answer 1

0

The issue was about Image component lazy-loading, which is fixed by installing sharp package or as a radical measure set preolading for Image

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.