Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid re-render in react using useRef?

I am creating a component to take photos and upload to a server. When I type something in the input box, the setTitle is trigger and the component is re-rendered. When this happens, the video went black. How can I avoid that the video was rendered?

function Camera() {
  console.log("Render camera");
  const [title, setTitle] = useState("");
  let videoRef = useRef(null);
  let canvasRef = useRef();

// This is a custom hook for get the camera input
  const mediaStream = useUserMedia({
    audio: false,
    video: { width: 300, height: 300 }
  });

  if (mediaStream && videoRef.current && !videoRef.current.srcObject) {
    videoRef.current.srcObject = mediaStream;
  }

  // Stop the video stream when component is unmount
  useEffect(() => {
    return () => {
      if (mediaStream) {
        mediaStream.getTracks()[0].stop();
      }
    };
  }, [mediaStream]);

  const handlePostTitle = e => {
    e.preventDefault();
    setTitle(e.target.value);
  };

  const onCapture = async blob => {
    console.log("Upload to server");
  };

  return (
    <form>
      <div>
        <video ref={videoRef} autoPlay muted />
        <canvas ref={canvasRef} width={300} height={300} />
      </div>
      <div>
        <input
          type="text"
          name="title"
          value={title}
          onChange={handlePostTitle}
          placeholder="Title"
        />
      </div>
      <button
        type="submit"
        onClick={() => {
          if (canvasRef) {
            const context = canvasRef.current.getContext("2d");
            // This is for rotate the photo
            context.translate(300, 0);
            context.scale(-1, 1);

            context.drawImage(videoRef.current, 0, 0, 300, 300);
            canvasRef.current.toBlob(blob => onCapture(blob), "image/jpeg", 1);
            context.clearRect(0, 0, 300, 300);
          }
        }}
      >
        Take photo
      </button>
    </form>
  );
}

The full code is available at https://codesandbox.io/s/react-camera-component-with-hooks-s6pmb

like image 455
Francisco Martin Avatar asked Jan 17 '20 18:01

Francisco Martin


1 Answers

Try this code, Codesandbox link - https://codesandbox.io/s/react-camera-component-with-hooks-n9ey9

import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import { useUserMedia } from "./hooks/use-user-media";

function Camera() {
  console.log("Render camera");
  let videoRef = useRef(null);
  let canvasRef = useRef();

  const mediaStream = useUserMedia({
    audio: false,
    video: { width: 300, height: 300 }
  });

  if (mediaStream && videoRef.current && !videoRef.current.srcObject) {
    videoRef.current.srcObject = mediaStream;
  }

  // Stop the video stream when component is unmount
  useEffect(() => {
    return () => {
      if (mediaStream) {
        mediaStream.getTracks()[0].stop();
      }
    };
  }, [mediaStream]);

  const onCapture = async blob => {
    console.log("Upload to server");
  };

  let titleRef = useRef();

  const OnSubmit = () => {
    console.log("title", titleRef.current.value);
  };

  return (
    <form>
      <div>
        <video ref={videoRef} autoPlay muted />
        <canvas ref={canvasRef} width={300} height={300} />
      </div>
      <div>
        <input type="text" name="title" placeholder="Title" ref={titleRef} />
      </div>
      <button
        type="submit"
        onClick={() => {
          OnSubmit();
          if (canvasRef) {
            const context = canvasRef.current.getContext("2d");
            // This is for rotate the photo
            context.translate(300, 0);
            context.scale(-1, 1);

            context.drawImage(videoRef.current, 0, 0, 300, 300);
            canvasRef.current.toBlob(blob => onCapture(blob), "image/jpeg", 1);
            context.clearRect(0, 0, 300, 300);
          }
        }}
      >
        Take photo
      </button>
    </form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Camera />, rootElement);
like image 175
Aldrin Avatar answered Nov 17 '22 01:11

Aldrin