最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React autoplay <video > (mp4) only when visible - Stack Overflow

programmeradmin1浏览0评论

I am writing a ponent 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 ponent 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 ponent 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 ponent 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(
      `=${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>
  );
}

I am writing a ponent 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 ponent 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 ponent 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 ponent 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./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>
  );
}
Share Improve this question edited Jun 30, 2020 at 1:40 Tristan asked Jun 30, 2020 at 0:30 TristanTristan 3714 silver badges19 bronze badges 2
  • Hey, did you find any solutions for this? – Diego Fortes Commented Sep 10, 2020 at 10:20
  • 1 @DiegoFortes I included my answer below – Tristan Commented Sep 15, 2020 at 4:10
Add a ment  | 

3 Answers 3

Reset to default 6

I ended up solving this one. I created a ponent for each gif and used a package called react-visibility-sensor to check if it was visible or not.
The GifDisplay ponent 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 ponent used react-visibility-sensor and updated the state of each ponent.

// 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>
  );
};

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

With react-intersection-observer you just have to make small adjustments to the SingleGif ponent.

const videoRef = useRef<HTMLVideoElement>(null);
const { ref, inView, entry } = useInView({
  /* Optional options */
  threshold: 0,
});

return(
  <div ref={ref}>
    <video
      ref={videoRef}
      ...
    />
  </div>
);
发布评论

评论列表(0)

  1. 暂无评论