0

How can I fix this error in react native:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app
import { cameraWithTensors } from "@tensorflow/tfjs-react-native";
import { Camera } from "expo-camera";
import { StatusBar } from "expo-status-bar";
import React, { useEffect, useState, useRef } from "react";
import {
  StyleSheet,
  Text,
  View,
  Platform,
  Dimensions,
  LogBox,
} from "react-native";
import * as cocoSsd from "@tensorflow-models/coco-ssd";
import { model } from "@tensorflow/tfjs";
import * as tf from "@tensorflow/tfjs";
import Canvas from "react-native-canvas";

const TensorCamera = cameraWithTensors(Camera);

const { width, height } = Dimensions.get("window");
let context = useRef<CanvasRenderingContext2D>();
let canvas = useRef<Canvas>();

export default function App() {
  const [model, setModel] = useState<cocoSsd.ObjectDetection>();

  let textureDims =
    Platform.OS === "ios"
      ? { height: 1920, width: 300 }
      : { height: 300, width: 300 };

  function handleCameraStream(images: any) {
    const loop = async () => {
      const nextImageTensor = images.next().value;
      if (!model || !nextImageTensor)
        throw new Error("No model or image tensor");
      model
        .detect(nextImageTensor)
        .then((predictions) => {
          drawRectangle(predictions, nextImageTensor);
        })
        .catch((error) => {
          console.log(error);
        });
      requestAnimationFrame(loop);
    };
    loop();
  }

  function drawRectangle(
    predictions: cocoSsd.DetectedObject[],
    nextImageTensor: any,
  ) {
    if (!context.current || !canvas.current) return;

    const scaleWidth = width / nextImageTensor.shape[1];
    const scaleHeight = height / nextImageTensor.shape[0];

    const flipHorizontal = Platform.OS == "ios" ? false : true;

    context.current.clearRect(0, 0, width, height);

    for (const prediction of predictions) {
      const [x, y, width, height] = prediction.bbox;

      const boundingBoxX = flipHorizontal
        ? canvas.current.width - x * scaleWidth - width * scaleWidth
        : x * scaleWidth;

      const boundingBoxY = y * scaleHeight;

      context.current.strokeRect(
        boundingBoxX,
        boundingBoxY,
        width * scaleWidth,
        height * scaleHeight,
      );

      context.current.strokeText(
        prediction.class,
        boundingBoxX - 5,
        boundingBoxY - 5,
      );
    }
  }

  async function handleCanvas(can: Canvas) {
    if (can) {
      can.width = width;
      can.height = height;
      const ctx: CanvasRenderingContext2D = can.getContext("2d");
      ctx.strokeStyle = "red";
      ctx.fillStyle = "red";
      ctx.lineWidth = 3;

      context.current = ctx;
      canvas.current = can;
    }
  }

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestPermissionsAsync();
      await tf.ready();
      setModel(await cocoSsd.load());
    })();
  }, []);

  return (
    <View style={styles.container}>
      <TensorCamera
        style={styles.camera}
        type={Camera.Constants.Type.back}
        cameraTextureHeight={textureDims.height}
        cameraTextureWidth={textureDims.width}
        resizeHeight={200}
        resizeDepth={3}
        onReady={handleCameraStream}
        autorender={true}
        useCustomShadersToResize={false}
        resizeWidth={0}
      />
      <Canvas style={styles.canvas} ref={handleCanvas} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
  },
  camera: { width: "100%", height: "100%" },
  canvas: {
    position: "absolute",
    zIndex: 1000000,
    width: "100%",
    height: "100",
  },
});

3 Answers 3

1

actual reason for this issue :- You are breaking the Rules of Hooks useRef() should call inside of the component

try this,

...
export default function App() {

  const context = useRef<CanvasRenderingContext2D>();
  const canvas = useRef<Canvas>();

  const [model, setModel] = useState<cocoSsd.ObjectDetection>();
...

}
Sign up to request clarification or add additional context in comments.

Comments

0

i think you called useRef outside of the component

...

let context = useRef();
let canvas = useRef();

export default function App() {
...
}

please call useRef inside of your App Component like this

...

    export default function App() {
      let context = useRef();
      let canvas = useRef();
      ...
    }

Comments

0

An important rule of using hooks is where you're declaring it. Hooks can be declared only inside of functions, which is predominantly at the top level, meaning it can only be declared at the top level and not within any nested function, block, or inside another hook(E.g: useEffect). The reason you're getting the error is that you're simply breaking the rules of hooks by declaring it outside of the function. Move the hook declaration within the function and you should be good to go. Also, recommend changing let to const as state variables are re-built on every render and not mutated.

export default function App() {
  const context = useRef<CanvasRenderingContext2D>();
  const canvas = useRef<Canvas>();
.
.
.
.
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.