Skip to content

Commit

Permalink
Control video playback using “playing” prop
Browse files Browse the repository at this point in the history
  • Loading branch information
weotch committed Sep 22, 2023
1 parent 608d8e8 commit f589a67
Showing 1 changed file with 36 additions and 3 deletions.
39 changes: 36 additions & 3 deletions packages/react/src/LazyVideo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"use client";

import { useInView } from 'react-intersection-observer'
import type { ReactElement } from 'react'
import { useEffect, type ReactElement, useRef, useCallback } from 'react'
import type { LazyVideoProps } from './types/lazyVideoTypes';

import { fillStyles, transparentGif } from './lib/styles'
Expand All @@ -12,11 +12,44 @@ export default function LazyVideo({
src, alt, fit, position, priority, noPoster, playing = true
}: LazyVideoProps): ReactElement {

// Make a ref to the video so it can be controlled
const videoRef = useRef<HTMLVideoElement>()

// Watch for in viewport to load video unless using priority
const { ref, inView } = useInView({
const { ref: inViewRef, inView } = useInView({
skip: priority
})

// Support multiple refs on the video. This is from the
// react-intersection-observer docs
const setRefs = useCallback((node: HTMLVideoElement) => {
videoRef.current = node
inViewRef(node)
}, [inViewRef])

// Store the promise that is returned from play to prevent errors when
// pause() is called while video is benginning to play.
const playPromise = useRef<Promise<void>>()

// Play the video, waiting until it's safe to play it. And capture any
// errors while trying to play.
const play = async () => {
if (playPromise.current) await playPromise.current
try { playPromise.current = videoRef.current?.play()}
catch (e) { console.error(e) }
}

// Pause the video, waiting until it's safe to play it
const pause = async () => {
if (playPromise.current) await playPromise.current
videoRef.current?.pause()
}

// Respond to playing prop and call methods that control the video playback
useEffect(() => {
playing ? play() : pause()
}, [ playing ])

// Simplify logic for whether to load sources
const shouldLoad = priority || inView

Expand All @@ -37,7 +70,7 @@ export default function LazyVideo({
poster={ noPoster ? transparentGif : undefined }

// Straightforward props
ref={ref}
ref={setRefs}
preload={ shouldLoad ? 'auto' : 'none' }
aria-label={ alt }
style={{
Expand Down

0 comments on commit f589a67

Please sign in to comment.