typescriptadvanced

useMediaRecorder Hook

Wraps the MediaRecorder API for audio/video recording with start, stop, and blob output.

typescript
import { useState, useRef, useCallback } from 'react';

interface UseMediaRecorderOptions {
  mimeType?: string;
  audio?: boolean;
  video?: boolean;
}

export function useMediaRecorder(options: UseMediaRecorderOptions = { audio: true }) {
  const [recording, setRecording] = useState(false);
  const [blob, setBlob] = useState<Blob | null>(null);
  const [error, setError] = useState<string | null>(null);
  const recorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);

  const start = useCallback(async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: options.audio ?? true,
        video: options.video ?? false,
      });
      const recorder = new MediaRecorder(stream, {
        mimeType: options.mimeType || 'audio/webm',
      });
      chunksRef.current = [];
      recorder.ondataavailable = (e) => chunksRef.current.push(e.data);
      recorder.onstop = () => {
        const recorded = new Blob(chunksRef.current, { type: recorder.mimeType });
        setBlob(recorded);
        stream.getTracks().forEach(t => t.stop());
      };
      recorder.start();
      recorderRef.current = recorder;
      setRecording(true);
      setError(null);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Recording failed');
    }
  }, [options]);

  const stop = useCallback(() => {
    recorderRef.current?.stop();
    setRecording(false);
  }, []);

  return { recording, blob, error, start, stop };
}

Use Cases

  • Voice memos
  • Video testimonials

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.