This is one of those things I wouldn't suggest you solve with the "roll your own" approach. There are some good libraries out there that will handle this and more. Uppy is one that comes to mind. I created and maintained another popular one for 7 years that i sunset in 2017.
Currently using react-dropzone seems to solve most of the major issues for me. Use that to get a signed URL via API, then upload from client to image server directly.
Many exploits involve running arbitrary code hidden in encoded image and video files, notably Pegasus among others. This should be treated as cryptography.