DEV Community

Christopher Evans
Christopher Evans

Posted on

Is it bad practice to make a POST call in useEffect?

Hi all,

I am using react-cropper for my users to upload/edit pictures, but when I try to console log the resulting photoData in my setPhotoData fn, the console log is one state behind. i.e. If I hit submit & upload and crop photo A, when setPhotoData runs it'll log an empty line in the console. Then when I do photo B, I'll get a console log of photo A's data. Uploading photo C will console log photo B's data and so on.

In a class component, you can add a callback after setState. So if I were using a class component I'd just make the POST there, after the state has been set. But apparently with react hooks you can't do that; my IDE gave me a warning and told me to use useEffect instead.

So now in useEffect I'm checking if photoData is populated in my state and then console logging once it is. This is working just fine for my little dev env: Nothing is logged until I hit submit, and then with the re-render that's triggered by the state change I get one console log with the correct cropped picture.

But I'm concerned that in production this is going to cause some kind of loop or leak. Even if I'm checking for defined state before I make the call, is there some potential for this to go wrong that I'm overlooking? It would similarly feel strange to do a POST in componentDidMount, so that's why I'm suspicious.

Here's the relevant code:

export const CropperWidget = () => {
  const [cropData, setCropData] = useState("");
  const [cropper, setCropper] = useState();

  const onChange = (e) => {
  // there's a fn to upload the file before cropping here
  }

  const getCropData = () => {
    if (typeof cropper !== "undefined") {
      setCropData(cropper.getCroppedCanvas().toDataURL());
    }
  };

  useEffect(() => {
    if (cropData) {
      console.log(cropData);
    }
  });

  return (
    // various irrelevant jsx
    <button onClick={getCropData}>Crop Image</button>
  );
};
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
rokkoo profile image
Alfonso

From my point of view if you construct your getCropData inside a useCallback and adding the cropper as a dependency your problem will be solved because the state of your function will always sync with your data because of the dependency.