如何在redux操作中处理XMLHttpRequests?

时间:2016-07-24 22:32:24

标签: javascript redux react-redux redux-form

我有一个redux-form,它将props传递给我的动作。属性this.props.userImages [0]是来自该表单上的文件输入的图像文件。然后,我正在将该图像和XMLHttpRequest制作成Cloudinary,为该图像生成一个URL。一旦我收到url数据(xhr.responseText),我想将其与我的其他道具合并,然后我可以将我的所有道具发布到API(所有表单信息+新创建的图像URL)。

我知道我必须等待我的请求才能生成一个url来解决,但是在我将其传递到我的其他函数之前遇到问题,该函数可以接收该信息并在发布之前将其合并到props中我的API。

//..

function generateUrl(props) {

     // Grabs image file from my form's file input and uploads 
     // to cloudinary service so that a URL can be generated

  const cloudinaryURL = 'https://api.cloudinary.com/v1_1/<my_name>/image/upload';
  const apiKey = 'secret_key';
  const uploadPreset = 'test_preset';

  const data = new FormData();
  data.append('file', props.userImages[0]);
  data.append('upload_preset', uploadPreset);
  data.append('api_key', apiKey);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', cloudinaryURL, true);
  xhr.send(data);
  xhr.onReadyStateChange = () => {
    if (xhr.readyState == 4 && xhr.status == 200) {
      return JSON.parse(xhr.responseText);
    }
  };

  return xhr.onReadyStateChange();
}

export function createReview(props) {

 const imageUrl = generateUrl(props);

 const mergedProps = //...

  // Here I'd like to merge my newly generated 
  // url back into props before I post to my API like so...

  const request = axios.post(`${REQUEST_URL}/api`, mergedProps)
  return {
    type: CREATE_REVIEW,
    payload: request
  }
};

非常感谢任何和所有帮助。

1 个答案:

答案 0 :(得分:1)

这与基于示例XMLHttpRequest的代码上下文中的promises无关。

您所做的假设是,分配给onReadyStateChange的回调会对其返回值执行某些操作。相反,从该函数返回的任何内容都会被尽职尽责。

你想要的是通过另一个回调传递值。

function generateUrl(props, callback) {
  // Do things here
    xhr.onReadyStateChange = () => {
      if (xhr.readyState == 4 && xhr.status == 200) {
        callback(JSON.parse(xhr.responseText));
      }
    };
}


generateUrl(props, (response) => {
  const mergedProps = // Use response as expected.
});

既然您提到了承诺并且您使用的是ES2015,我们可以将其转换为实际使用的承诺,这可能是您想要开始的。

function generateUrl(props) {
  return new Promise((resolve, reject) => {
    const cloudinaryURL = 'https://api.cloudinary.com/v1_1/<my_name>/image/upload';
    const apiKey = 'secret_key';
    const uploadPreset = 'test_preset';

    const data = new FormData();
    data.append('file', props.userImages[0]);
    data.append('upload_preset', uploadPreset);
    data.append('api_key', apiKey);

    const xhr = new XMLHttpRequest();
    xhr.onReadyStateChange = () => {
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          resolve(xhr.responseText);
        } else {
          reject(new Error(`Failed HTTP request (${xhr.status})`));
        }
    };
    xhr.onerror = reject;

    xhr.open('POST', cloudinaryURL, true);
    xhr.send(data);
  });
}

generateUrl(props)
  .then(JSON.parse)
  .then(results => {
    // Do something with response
  })
  .catch(error => {
    // Do something with the error
  });