title: How should customRequest be set in the Ant Design Upload component to work with an XMLHttpRequest?
body: <p>I have a complete mess of a component. Right now I pass a function I have been trying a million things I can not make it work.</p>
  
  <pre><code>export default class DatafileUpload extends Component {
    initialState = {
      fileUploading: false,
      fileList: [],
      status: 'empty', // 'empty' | 'active' | 'success' | 'exception'
      file: {}
    }
  
    state = this.initialState
  
    static propTypes = {
      userId: PropTypes.string.isRequired,
      datasetId: PropTypes.string.isRequired
    }
  
    scrubFilename = (filename) =&gt; filename.replace(/[^\w\d_\-.]+/ig, '')
  
    requestSignedS3Url = (file) =&gt; {
      const filename = this.scrubFilename(file.name)
      const params = {
        userId: this.props.userId,
        contentType: file.type,
        Key: `${filename}`
      };
      return api.get('/s3/signUpload', { params })
        .then(response =&gt; {
          return response.data;
        })
        .catch(error =&gt; {
          console.error(error);
        });
    }
  
    uploadFile = (file) =&gt; {
      this.requestSignedS3Url(file)
        .then(signResult =&gt; this.uploadToS3(file, signResult))
        .catch(error =&gt; console.log(error))
    }
  
    createCORSRequest = (method, url, opts) =&gt; {
      opts = opts || {};
      let xhr = new XMLHttpRequest();
      if (xhr.withCredentials != null) {
        xhr.open(method, url, true);
        if (opts.withCredentials != null) {
          xhr.withCredentials = opts.withCredentials;
        }
      } else if (typeof XDomainRequest !== "undefined") {
        xhr = new XDomainRequest();
        xhr.open(method, url);
      } else {
        xhr = null;
      }
      return xhr;
    };
  
    stepFunctions = () =&gt; {
      return {
        preprocess: (file) =&gt; {
          console.log('Pre-process: ' + file.name);
        },
        onProgress: (percent, message, file) =&gt; {
          this.setState({ fileUploading: true })
          console.log('Upload progress: ' + percent + '% ' + message);
        },
        onFinish: (signResult) =&gt; {
          this.setState({ fileUploading: false })
          console.log("Upload finished: " + signResult.publicUrl)
        },
        onError: (message) =&gt; {
          this.setState({ fileUploading: false })
          console.log("Upload error: " + message);
        },
        scrubFilename: (filename) =&gt; {
          return filename.replace(/[^\w\d_\-\.]+/ig, '');
        },
        onFinishS3Put: (signResult, file) =&gt; {
          console.log(signResult)
          return console.log('base.onFinishS3Put()', signResult.publicUrl);
        }
      }
    }
  
    uploadToS3 = async (file, signResult) =&gt; {
      const xhr = await this.createCORSRequest('PUT', signResult.signedUrl);
      const functions = this.stepFunctions()
      functions.preprocess(file)
      if (!xhr) {
        functions.onError('CORS not supported', file);
      } else {
        xhr.onload = () =&gt; {
          if (xhr.status === 200) {
            functions.onProgress(100, 'Upload completed', file);
            return functions.onFinishS3Put('potatopotato', file);
          } else {
            return functions.onError('Upload error: ' + xhr.status, file);
          }
        };
        xhr.onerror = () =&gt; {
          return functions.onError('XHR error', file);
        };
        xhr.upload.onprogress = (e) =&gt; {
          let percentLoaded;
          if (e.lengthComputable) {
            percentLoaded = Math.round((e.loaded / e.total) * 100);
            return functions.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing' : 'Uploading', file);
          }
        };
      }
      xhr.setRequestHeader('Content-Type', file.type);
      if (signResult.headers) {
        const signResultHeaders = signResult.headers
        Object.keys(signResultHeaders).forEach(key =&gt; {
          const val = signResultHeaders[key];
          xhr.setRequestHeader(key, val);
        })
      }
      xhr.setRequestHeader('x-amz-acl', 'public-read');
      this.httprequest = xhr;
      return xhr.send(file);
    };
  
    handleChange = ({ file, fileList }) =&gt; {
      const functions = this.stepFunctions()
      functions.preprocess(file)
      if (!file) {
        functions.onError('CORS not supported', file);
      } else {
        file.onload = () =&gt; {
          if (file.status === 200) {
            functions.onProgress(100, 'Upload completed', file);
            return functions.onFinishS3Put('potatopotato', file);
          } else {
            return functions.onError('Upload error: ' + file.status, file);
          }
        };
        file.onerror = () =&gt; {
          return functions.onError('XHR error', file);
        };
        file.upload.onprogress = (e) =&gt; {
          let percentLoaded;
          if (e.lengthComputable) {
            percentLoaded = Math.round((e.loaded / e.total) * 100);
            return functions.onProgress(percentLoaded, percentLoaded === 100 ? 'Finalizing' : 'Uploading', file);
          }
        };
      }
      console.log('File: ', file)
      // always setState
      this.setState({ fileList });
    }
  
    render() {
      const props = {
        onChange: this.handleChange,
        multiple: true,
        name: "uploadFile",
        defaultFileList: this.initialState.fileList,
        data: this.uploadFile,
        listType: "text",
        customRequest: ????,
        showUploadList: {
          showPreviewIcon: true,
          showRemoveIcon: true
        },
        onProgress: ( {percent} ) =&gt; {
          this.setState({ fileUploading: true })
          console.log('Upload progress: ' + percent + '% ' );
        },
        onError: (error, body) =&gt; {
          this.setState({ fileUploading: false })
          console.log("Upload error: " + error);
        },
        onSuccess: (body)=&gt; {
          console.log(body)
          return console.log('base.onFinishS3Put()');
        }
      };
  
      return (
        &lt;Upload {...props} fileList={this.state.fileList}&gt;
          &lt;Button&gt;
            &lt;Icon type="upload" /&gt; Upload
          &lt;/Button&gt;
        &lt;/Upload&gt;
      )
    }
  }
  </code></pre>
  
  <p>I know this code is a mess that doesn't make sense and have duplicated data all around. I want it to make it work and then clean up/optimse. Basically I am not able to make the component progress bar update nor with the <code>onChange</code> nor when I am trying to use the <code>customRequest</code>. When is <code>customRequest</code> called? <a href="https://github.com/react-component/upload#customrequest" rel="noreferrer">This</a> is not very abundant in explanations... I don't understand how does it do the replacement of Ajax upload.</p>