2019-11-07
2580
#react
Andrew James
9113
Nov 7, 2019 ⋅ 9 min read

Building a responsive camera component with React Hooks

Andrew James Frontend Engineer @ Coinbase

Recent posts:

Exploring Nushell, A Rust Powered, Cross Platform Shell

Exploring Nushell, a Rust-powered, cross-platform shell

Nushell is a modern, performant, extensible shell built with Rust. Explore its pros, cons, and how to install and get started with it.

Oduah Chigozie
Apr 23, 2024 ⋅ 6 min read
Exploring Zed, A Newly Open Source Code Editor Written In Rust

Exploring Zed, an open source code editor written in Rust

The Zed code editor sets itself apart with its lightning-fast performance and cutting-edge collaborative features.

Nefe Emadamerho-Atori
Apr 22, 2024 ⋅ 7 min read
Implementing Infinite Scroll In Next Js With Server Actions

Implementing infinite scroll in Next.js with Server Actions

Infinite scrolling in Next.js no longer requires external libraries — Server Actions let us fetch initial data directly on the server.

Rahul Chhodde
Apr 19, 2024 ⋅ 10 min read
Integrating Django Templates With React For Dynamic Webpages

Integrating Django templates with React for dynamic webpages

Create a dynamic demo blog site using Django and React to demonstrate Django’s server-side functionalities and React’s interactive UI.

Kayode Adeniyi
Apr 18, 2024 ⋅ 7 min read
View all posts

7 Replies to "Building a responsive camera component with React Hooks"

  1. This was really helpful in learning. I noticed that the main camera component is capitalized, but the supporting functions like useUserMedia are not. As a best practice where should those supporting functions live? Guessing not in a folder like Camera would inside of a Components folder.

  2. Super helpful, thank you for posting this.

    However your useUserMedia wasn’t working properly for me, so I refactored it like this:

    import { useState, useEffect } from “react”;

    export function useUserMedia(requestedMedia) {
    const [mediaStream, setMediaStream] = useState(null);

    useEffect(() => {
    // Creating reference at the top of useEffect’s scope for cleanup later
    let streamRef = null;

    async function enableStream() {
    try {
    // Using ref instead of a new const variable
    streamRef = await navigator.mediaDevices.getUserMedia(requestedMedia);
    setMediaStream(streamRef);
    } catch(err) {
    // Removed for brevity
    }
    }

    if (!mediaStream) {
    enableStream();
    }

    // Removed else block
    return function cleanup() {
    // Now the ref can be used to stop all media tracks
    streamRef.getTracks().forEach(track => {
    track.stop();
    });
    }

    // Removed dependency array
    }, []);

    return mediaStream;

    Now when the component unmounts, the camera stops recording.

    1. I had a similar issue, but in dev mode the cleanup function was running before the getUseMedia promise resolved, so the streamRef was null when cleanup ran and the MediaStream wasn’t closed. This meant that when I clicked “Take a picture”, the webcam stayed on.

      The way I got around this was by using a streamRefArray outside of the useEffect and pushing each new stream into that instead of reassigning the the streamRef variable. Then, on cleanup, I’d loop through the streamRefArray MediaStreams and stop all their tracks. This seemed to do the trick.

      import { useState, useEffect } from “react”

      export function useUserMedia(requestedMedia: MediaStreamConstraints) {
      const [mediaStream, setMediaStream] = useState(null)
      let streamRefArray: MediaStream[] = []

      useEffect(() => {
      async function enableStream() {
      try {
      const stream = await navigator.mediaDevices.getUserMedia(requestedMedia)
      // Push media stream to reference array
      // to stop track in later cleanup
      streamRefArray.push(stream)
      setMediaStream(stream)
      } catch (err) {
      console.error(err)
      }
      }

      if (!mediaStream) {
      enableStream()
      }

      return function cleanup() {
      // Loop through array of media streams
      streamRefArray.forEach((stream) => {
      stream?.getTracks().forEach((track) => {
      console.log(track)
      track.stop()
      })
      streamRefArray = []
      })
      }
      }, [])

      return mediaStream
      }

  3. Hi Andrew,
    Can you please shed some light on how to resize the container for mobile devices, as for the mobile devices i need height > width.
    Thanks in Advance.

Leave a Reply