如何在 redux 操作中处理 XMLHttpRequests?

How to handle XMLHttpRequests in a redux action?

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

我知道我必须等待我的请求生成一个 url 来解决,但是在我将它传递到我的其他函数之前遇到了问题,它可以获取该信息并合并它在 post 进入我的 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
  }
};

非常感谢任何帮助。

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

您所做的假设是分配给 onReadyStateChange 的回调对其 return 值执行某些操作。相反,从该函数 return 编辑的任何内容都将被尽职地忽略。

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

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.
});

由于您提到了 promise 并且您使用的是 ES2015,我们可以将其转换为实际使用 promises,这可能正是您想要开始的。

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
  });