简体   繁体   English

next.js 中的无限 requestAnimationFrame 循环

[英]infinite requestAnimationFrame Loop in next.js

I am trying to recreate this app in next.js https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#0我正在尝试在next.js https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#0中重新创建此应用程序

To start the data collection, I added a onMouseDown MouseEvent on the button which, triggers this code:为了开始数据收集,我在按钮上添加了一个onMouseDown MouseEvent ,触发以下代码:

const handleGatherDataForClass: MouseEventHandler = (e) => {
  let classNumber = parseInt(e.target.getAttribute('data-1hot'));
  console.log('inside EventHandler:', { classNumber });
  let state = gatherDataState === STOP_DATA_GATHER ? classNumber : STOP_DATA_GATHER;
  console.log({ state });
  setGatherDataState(state);
};

Where在哪里

  • classNumber = positive integer classNumber = 正 integer

  • STOP_DATA_GATHER = -1 STOP_DATA_GATHER = -1

  • gatherDataState = -1 (default) gatherDataState = -1 (默认)

Here is the original code snippet from the working app: https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#11这是工作应用程序的原始代码片段: https://codelabs.developers.google.com/tensorflowjs-transfer-learning-teachable-machine#11

After the state of the gatherDataState variable changes, the useEffect hook should run the dataGatherLoop function, which takes frames from the video stream and converts it into tensors:gatherDataState变量的state改变后, useEffect钩子应该运行dataGatherLoop function,它从视频ZF7B44CFAFD5C52223D5498196C8A2E7B中取帧并转换成张量:

useEffect(() => {
  dataGatherLoop();
}, [gatherDataState]);


function dataGatherLoop() {
  console.log('inside Loop: ', {
    gatherDataState
  });

  if (videoPlaying && gatherDataState !== STOP_DATA_GATHER) {
    let imageFeatures = tf.tidy(function() {
      let videoFrameAsTensor = tf.browser.fromPixels(VIDEO);
      let resizedTensorFrame = tf.image.resizeBilinear(
        videoFrameAsTensor, [MOBILE_NET_INPUT_HEIGHT, MOBILE_NET_INPUT_WIDTH],
        true
      );
      let normalizedTensorFrame = resizedTensorFrame.div(255);
      return mobilenet.predict(normalizedTensorFrame.expandDims()).squeeze();
    });
    imageFeatures.print();

    setTrainData((prev) => ({
      trainX: [...prev.trainX, imageFeatures],
      trainY: [...prev.trainY, gatherDataState],
    }));

    // Intialize array index element if currently undefined.
    let newCount = [...examplesCount];
    if (examplesCount[gatherDataState] === undefined) {
      newCount[gatherDataState] = 1;
      setExamplesCount(newCount);
    } else {
      newCount[gatherDataState]++;
      setExamplesCount(newCount);
    }


    window.requestAnimationFrame(dataGatherLoop);
  }
}

This loop runs, as long as the gatherDataState variable is a positive integer (not equal to -1 ) After the mouse button is released, an onMouseUp event is triggered which runs the same handleGatherDataForClass function as the onMouseDown event.只要gatherDataState变量是正数integer(不等于-1 ),此循环就会运行。释放鼠标按钮后,将触发一个onMouseUp事件,该事件运行与onMouseDown事件相同的handleGatherDataForClass function。 This should change the state back to -1 and therefore stop the Loop.这应该将 state 改回-1并因此停止循环。

Problem:问题:
Even though the state is changing to -1 after the onMouseUp event is triggered, the gatherDataState ends up being a positive integer every time.. Therefore the loop is not stopping.即使在触发onMouseUp事件后 state 变为-1gatherDataState最终每次都是正 integer ..因此循环不会停止。 (there is NO setGatherDataState function anywhere else in the code) (代码中的其他任何地方都没有setGatherDataState function)

I tried:我试过了:

  • writing the gatherDataLoop function inside the handleGatherDataForClass event handler and passing the gatherDataState variable as an argumenthandleGatherDataForClass事件处理程序中编写gatherDataLoop function并将gatherDataState变量作为参数传递
  • using a global variable for gatherDataState instead of a react state to save the current gatherDataState使用gatherDataState的全局变量而不是反应state来保存当前的gatherDataState
  • canceling the requestAnimationFrame loop with the cancelAnimationFrame function (saving the id globally and as state)使用cancelAnimationFrame function 取消requestAnimationFrame循环(全局保存 id 并保存为状态)

I am not exactly sure why, but我不确定为什么,但是

  • using useRef to store the values being used inside the requestAnimationFrame loop, as well as the id for canceling the loop and使用 useRef 存储在 requestAnimationFrame 循环中使用的值,以及用于取消循环的 id 和
  • taking the loop out of the useEffect Hook and writing it inside the ClickEventhandler从 useEffect Hook 中取出循环并将其写入 ClickEventhandler

worked for me.为我工作。 Here is the code:这是代码:

 const handleGatherDataForClass: MouseEventHandler = (e) => {
    let classNumber = parseInt(e.target.getAttribute('data-1hot'));
    gatherDataStateRef.current = classNumber;
    isCollectingRef.current = !isCollectingRef.current;
    if (isCollectingRef.current) {
      collectRequestRef.current = requestAnimationFrame(dataGatherLoop);
    } else {
      cancelAnimationFrame(collectRequestRef.current);
    }
  };


function dataGatherLoop() {
    console.log('inside Loop: ', gatherDataStateRef.current);

    let imageFeatures = tf.tidy(function () {
      let videoFrameAsTensor = tf.browser.fromPixels(VIDEO);
      let resizedTensorFrame = tf.image.resizeBilinear(
        videoFrameAsTensor,
        [MOBILE_NET_INPUT_HEIGHT, MOBILE_NET_INPUT_WIDTH],
        true
      );
      let normalizedTensorFrame = resizedTensorFrame.div(255);
      return mobilenet.predict(normalizedTensorFrame.expandDims()).squeeze();
    });
    imageFeatures.print();

    setTrainData((prev) => ({
      trainX: [...prev.trainX, imageFeatures],
      trainY: [...prev.trainY, gatherDataStateRef.current],
    }));

    if (examplesCountRef.current[gatherDataStateRef.current] === undefined) {
      examplesCountRef.current[gatherDataStateRef.current] = 1;
    } else {
      examplesCountRef.current[gatherDataStateRef.current] += 1;
    }

    collectRequestRef.current = requestAnimationFrame(dataGatherLoop);
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM