SCALE — Build Lab
UI部品 · REACT COMPONENT

音声録音(ブラウザ完結)

CATEGORYUI部品 TYPEReact Component EFFORT120〜240分 DIFFICULTY
PRIMARY CODE
tsx
export function AudioRecorder({ onSave }: { onSave: (blob: Blob) => void }) {
  const [recording, setRecording] = useState(false);
  const recorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);

  const start = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    const recorder = new MediaRecorder(stream);
    chunksRef.current = [];
    recorder.ondataavailable = (e) => chunksRef.current.push(e.data);
    recorder.onstop = () => {
      const blob = new Blob(chunksRef.current, { type: 'audio/webm' });
      onSave(blob);
      stream.getTracks().forEach(t => t.stop());
    };
    recorder.start();
    recorderRef.current = recorder;
    setRecording(true);
  };
  const stop = () => { recorderRef.current?.stop(); setRecording(false); };

  return recording
    ? <button onClick={stop}>■ 停止</button>
    : <button onClick={start}>● 録音開始</button>;
}
前提条件
Tailwind CSS v4TypeScript 5
USE CASES
  • 議事録
  • ボイスメモ
  • 面接録音

音声録音(ブラウザ完結)

:LiTarget: 用途

ブラウザマイクで録音 → WebM/MP3 でアップロード。

:LiSparkle: 特徴

  • 録音/停止/再生
  • 波形表示
  • アップロード

:LiCode: コード(コピペ用)

export function AudioRecorder({ onSave }: { onSave: (blob: Blob) => void }) {
  const [recording, setRecording] = useState(false);
  const recorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);

  const start = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    const recorder = new MediaRecorder(stream);
    chunksRef.current = [];
    recorder.ondataavailable = (e) => chunksRef.current.push(e.data);
    recorder.onstop = () => {
      const blob = new Blob(chunksRef.current, { type: 'audio/webm' });
      onSave(blob);
      stream.getTracks().forEach(t => t.stop());
    };
    recorder.start();
    recorderRef.current = recorder;
    setRecording(true);
  };
  const stop = () => { recorderRef.current?.stop(); setRecording(false); };

  return recording
    ? <button onClick={stop}>■ 停止</button>
    : <button onClick={start}>● 録音開始</button>;
}

:LiHandPointer: 使い方

対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。

:LiAlertCircle: 注意事項

  • 依存パッケージを忘れず追加