【问题标题】:Re-rendering React component when I call useState hook当我调用 useState 挂钩时重新渲染 React 组件
【发布时间】:2019-11-14 07:52:15
【问题描述】:

当我在 image.onload() 中调用 useState() 挂钩时,我遇到了重新渲染 React 组件的问题。我希望组件在我调用setClassificationResult 后重新渲染一次,但由于某种原因,它一直在重新渲染,就像我有一些无限循环一样。这是我的代码:

const ImageClassification = React.memo(function() {
  const [isModelLoaded, setModelLoaded] = useState(false);
  const [uploadedFile, setUploadedFile] = useState();
  const [classifier, setClassifier] = useState();
  const [classificationResult, setClassificationResult] = useState();

  useEffect(() => {
    async function modelReady() {
      setClassifier(
        await MobileNet.load().then(model => {
          setModelLoaded(true);
          return model;
        })
      );
    }

    modelReady();
  }, []);

  function onDrop(acceptedFiles: File[]) {
    setUploadedFile(acceptedFiles);
  }

  function prepareImage(inputFile: File) {
    const image = new Image();
    let fr = new FileReader();

    fr.onload = function() {
      if (fr !== null && typeof fr.result == "string") {
        image.src = fr.result;
      }
    };
    fr.readAsDataURL(inputFile);

    image.onload = async function() {
      const tensor: Tensor = tf.browser.fromPixels(image);
      classifier.classify(tensor).then((result: any) => {
        // Crazy re-rendering happens when I call this hook.
        setClassificationResult(result);
        console.log(result);
      });
      console.log("Tensor" + tensor);
    };
  }

  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

  return (
    <React.Fragment>
      {!isModelLoaded ? (
        <CircularProgress />
      ) : (
        <div {...getRootProps()}>
          <input {...getInputProps()} />
          {isDragActive ? (
            <p>Drop the files here.. </p>
          ) : (
            <p>Drag 'n' drop some files here, or click to select files</p>
          )}
          {uploadedFile &&
            uploadedFile.map((item: File) => {
              prepareImage(item);
              return classificationResult
                ? classificationResult.map((result: any) => {
                    return (
                      <ClassificationResult
                        className={result.className}
                        probability={result.probability}
                      />
                    );
                  })
                : null;
            })}
        </div>
      )}
    </React.Fragment>
  );
});

export default ImageClassification;

知道如何避免这种疯狂的重新渲染吗?

【问题讨论】:

  • 如果您更新状态,组件将重新渲染。你到底想达到什么目的?
  • 我希望组件重新渲染一次,但它一直在重新渲染,而不仅仅是一次。我要做的是将分类结果设置为classificationResult,然后在组件中呈现结果。我也会更新问题。

标签: reactjs typescript react-hooks tensorflow.js


【解决方案1】:

您的组件存在生命周期问题,因为它从您的 return html 值调用 prepareImage(item)。这意味着您将在每次渲染时调用此函数,这就是为什么它会创建一些无限循环的疯狂重新渲染。

您需要重新考虑您的算法并将其移至更好的位置。一个好的解决方案是只prepareImage onDrop event 所以它只做一次。

function onDrop(acceptedFiles: File[]) {
    setUploadedFile(acceptedFiles);
    acceptedFiles.forEach(file => {
        prepareImage(file);
    });
}

然后可能在状态中存储一个 图像数组,应该显示并准备好 ?。

【讨论】:

  • 谢谢,这很有意义:)
猜你喜欢
  • 2021-04-13
  • 2020-03-12
  • 2020-10-29
  • 2020-07-12
  • 2020-01-26
  • 2019-08-07
  • 2021-03-10
  • 2021-03-05
  • 2022-01-17
相关资源
最近更新 更多