简体   繁体   中英

Re-rendering React component when I call useState hook

I have a problem with the re-rendering React component when I call useState() hook inside image.onload() . I'm expecting the component to be re-render once after I call setClassificationResult , but of some reason, it's re-rendering all the time, like I have some infinite loop. Here is my code:

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;

Any idea of how to avoid that crazy re-rendering?

You have a lifecycle issue with your component, as it call prepareImage(item) from your return html value. This means you will call this function at each rendering which is why it create some infinite-loop crazy re-redering.

You need to rethink your algorithm and move it to a better location . A good solution would to only prepareImage onDrop event so it is done only once.

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

Then maybe store in state an array of Image which should be dislayed and be prepared.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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