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:

next js link component

How to use the Next.js Link component to optimize navigation

With features like automatic prefetching and seamless integration with dynamic routing, Link helps you create a fast and responsive web application.

Chimezie Innocent
Mar 31, 2025 ⋅ 5 min read
tanstack table react table

A complete guide to TanStack Table (formerly React Table)

Discover how to use TanStack Table, formerly known as React Table, to build a table UI for a variety of use cases.

Paramanantham Harrison
Mar 28, 2025 ⋅ 14 min read
javascript object prototypes

JavaScript prototypes: How objects inherit properties and methods

Explore what prototypes are, how the prototype chain works, and how to use the prototype chain to create inheritance between objects.

Ibadehin Mojeed
Mar 28, 2025 ⋅ 7 min read
set up Node.js with TypeScript and Express

How to set up TypeScript with Node.js and Express

Set up TypeScript with Node.js and Express, focusing on configuring key elements for a smooth development experience.

Aman Mittal
Mar 28, 2025 ⋅ 9 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