3

I am writing a component that pulls gifs from Giphy and renders them inside a React Infinite Scroll Component. The infinite scroll is worked as expected, but then I ran into a problem. I want the gifs to auto play, so I added the autoplay attribute. I then realised that with all of the gifs playing at once the performance just dies.
I have tried a number of different solutions, including attaching a ref to each video component and using react-visibility-sensor to try to play when visible, but I have not been able to work out a way that works.
This is the component as it currently stands with each mp4 autoplaying. I have removed the VisibilitySensor because I could not get it working.

  const videoRefs = useRef(
    [...new Array(gifArray.length)].map(() => createRef()),
  );

  return (
    <div>
      {gifArray && (
        <InfiniteScroll
          dataLength={gifArray}
          next={getMore}
          hasMore={true}
          loader={<div>Loading...</div>}
        >
          {gifArray.map((gif, i) => {
            return (
              <video
                width='320'
                height='240'
                loop
                autoPlay
                key={gif.id}
                ref={videoRefs.current[i]}
              >
                <source src={gif.images.downsized_small.mp4} type='video/mp4' />
              </video>
            );
          })}
        </InfiniteScroll>
      )}
    </div>
  );
};

The data is retrieved in a seperate component and passed as props.

export const HomePage = () => {
  const [gifObject, setGifObject] = useState([]);
  const [searchValue, setSearchValue] = useState('');
  const [pageNumber, setPageNumber] = useState(0);

  const handleSearch = (value) => {
    setSearchValue(value);
    fetch(
      `http://api.giphy.com/v1/gifs/search?q=${value}&api_key=${API_KEY}&limit=20`,
    )
      .then((data) => data.json())
      .then((result) => {
        setGifObject(result);
      });
  };
  return (
    <div>
      <SearchForm handleSearchValue={handleSearch} />
      {gifObject?.data?.length > 1 ? (
        <GifDisplay gifArray={gifObject.data} getMore={getData} />
      ) : null}
    </div>
  );
}
Tristan
  • 341
  • 4
  • 17

2 Answers2

5

I ended up solving this one. I created a component for each gif and used a package called react-visibility-sensor to check if it was visible or not.
The GifDisplay component remained pretty close to the same:

// GifDisplay.tsx
export const GifDisplay = ({ gifArray, getMore, handleSearch }) => {
  return (
    <GifDisplayWrapper>
      {gifArray && (
        <InfiniteScroll
          dataLength={gifArray}
          next={getMore}
          hasMore={true}
          loader={<div>Loading...</div>}
        >
          <ArrayWrapper>
            {gifArray.map((gif) => {
              return (
                <div key={gif.id}>
                  <SingleGif gif={gif} />
                </div>
              );
            })}
          </ArrayWrapper>
        </InfiniteScroll>
      )}
    </GifDisplayWrapper>
  );
};

The SingleGif component used react-visibility-sensor and updated the state of each component.

// SingleGif.tsx
import VisibilitySensor from 'react-visibility-sensor';

export const SingleGif = ({ gif }) => {
  const videoRef = useRef(null);
  const [isVisible, setIsVisible] = useState(false);

  useEffect(() => {
    if (isVisible) {
      videoRef.current.play();
    } else {
      if (videoRef.current.play) {
        videoRef.current.pause();
      }
    }
  }, [isVisible]);

  return (
    <VisibilitySensor onChange={(isVisible) => setIsVisible(isVisible)}>
      <video width='320' height='240' loop ref={videoRef}>
        <source src={gif.images.downsized_small.mp4} type='video/mp4' />
      </video>
    </VisibilitySensor>
  );
};
Tristan
  • 341
  • 4
  • 17
  • 1
    `react-visibility-sensor` project is dead. Now use `react-intersection-observer` instead – user Nov 24 '21 at 14:45
0

Use react-intersection-observer instead of react-visibility-sensor as above commented by someone. react-visibility-sensor is no more available for this.

Muhammad Talha
  • 719
  • 1
  • 4
  • 9