Repository: h2oai/wave
File: ui/src/file_upload.tsx (TypeScript)

Code before:
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      rejectXhr = React.useRef<(reason?: any) => void>(),
      xhrRef = React.useRef<XMLHttpRequest>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            xhrRef.current = new XMLHttpRequest()
            rejectXhr.current = reject
            const xhr = xhrRef.current
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              xhr.status >= 200 && xhr.status < 300 ? resolve(xhr) : reject(xhr)
            }
          })
          const { files } = JSON.parse(responseText)
          wave.args[name] = files

          if (!compact) wave.push()
          setSuccessMsg(`Successfully uploaded files: ${files.map(({ name }: File) => name).join(',')}.`)
        }
        catch (err: unknown) {
          if (err) {
            let errMsg = 'There was an error when uploading file.'
            if (err instanceof XMLHttpRequest) {
              errMsg = err.responseText
            }
            setError(errMsg)
          }
        }
        finally {

Review comment (suggestion):
We can take advantage the power of JS closures and get rid of `xhrRef` as well.

```suggestion
            rejectXhr.current = () => {
               reject()
               xhr.abort()
               setPercentComplete(0)
            }
```

Code after:
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      rejectXhr = React.useRef<(reason?: any) => void>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            rejectXhr.current = () => {
              reject()
              xhr.abort()
              setPercentComplete(0)
            }
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              xhr.status >= 200 && xhr.status < 300 ? resolve(xhr) : reject(xhr)
            }
          })
          const { files } = JSON.parse(responseText)
          wave.args[name] = files

          if (!compact) wave.push()
          setSuccessMsg(`Successfully uploaded files: ${files.map(({ name }: File) => name).join(',')}.`)
        }
        catch (err: unknown) {
          if (err) setError(err instanceof XMLHttpRequest ? err.responseText : 'There was an error when uploading file.')
          setFileNames('')
        }
        finally {
          setFiles([])
        }
      },