Kevin Kevin - 4 months ago 59
React JSX Question

Using redux-api-middleware to process image/jpeg content

I have an RSAA (Redux Standard API-calling Action) that I'm using to retrieve

image/jpeg
content. All the examples I've seen deal with JSON data so I copied the
getJSON
function and implemented my own
getImage
function to deal with this content type. The problem I'm now running into is that this blob needs to be converted to base64 and that has to be done using an async function. So, my FSA gets triggered before this async operation completes.

I suspect that I need to somehow piggyback on the existing promise chain in the RSAA
payload
processing but I'm not sure how to do this.

Here's the snippet of code with the line commented where I need to perform the promise
resolve
to return this result:

export function fetchSiteThumbnailImage(endpoint) {
return {
[CALL_API]: {
endpoint,
method: 'GET',
headers: {
'Accept': 'image/jpeg'
},
types: [
LOAD_SITE_THUMBNAIL_REQUEST,
{
type: LOAD_SITE_THUMBNAIL_SUCCESS,
payload: (action, state, res) => {
return getImage(res).then((blob) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
const base64data = reader.result;
return base64data; // this needs to "resolve" - how??
}
});
},
meta: (action, state, res) => {
return {
siteId,
endpoint
}
}
},
LOAD_SITE_THUMBNAIL_FAILURE
]
}
}
}


Thanks!

Answer

You have to wrap your FileReader logic into a Promise:

function readAsBase64(blob) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => {
            const base64data = reader.result;
            resolve(base64data);
        }
        reader.onerror = (err) => {
            reject(err);
        }
        reader.readAsDataURL(blob); 
    });
}

Your payload function can then just be

(action, state, res) => getImage(res).then(readAsBase64);

A couple of notes:

  • reader.onloadend gets called when the reading operation is completed (either in success or in failure), while reader.onload is called only on successful completion and reader.onerror only on failed completion — you want to separate the two cases.

  • You should set the event handlers before you start reading the blob to avoid race conditions — so put reader.readAsDataURL at the end.