CpILL CpILL - 1 month ago 17
React JSX Question

Redux-Saga non-ajax related callback issue

So, i'm having a hard time trying to figure out how to convert the following example to using sagas as its not an ajax related async problem:

var dogBarkingBuffer = null;
// Fix up prefixing
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();

function loadDogSound(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';

// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
dogBarkingBuffer = buffer;
}, onError);
}
request.send();
}


The problem i'd finding is not the
XMLHttpRequest
related stuff but rather how to deal with the
decodeAudioData(data, callback)
which only gives you the returned data via a callback and thus I want to trigger an action i there to add this to my Redux store.

My saga looks like this at the moment but the missing yield in front of decodeAudio seems like a problem:

import { takeLatest } from "redux-saga";
import { call, put } from "redux-saga/effects";
import axios from "axios";

import * as acts from "actions/playList";


const audioFileRequest = (url) => {
return axios.get(url, {
withCredentials: true,
responseType: "arraybuffer",
})
.then(({ data }) => data)
.catch(({ error }) => error);
};

const decodeAudio = (undecodedData, audioContext) => {
return audioContext.decodeAudioData(undecodedData, (buffer) => {
acts.recivedAudioFile(buffer); // no yeald ???
});
};

function *fetchAudio({ url, audioContext }) {
try {
let rawAudioData = yield call(audioFileRequest, url);
decodeAudio(rawAudioData, audioContext); // no yield ???
}
catch (error) {
yield put(acts.errorFetchingAudioFile(error));
}
}

export function *watchFetchAudio() {
yield takeLatest(acts.AUDIO_FILE_REQUEST, fetchAudio);
}

Answer

I think you can convert the decode audio function using es6-promise and use redux saga call method.

const decodeAudio = ({rawAudioData, audioContext}) => {
    return new Promise((resolve, reject) => {
        audioContext.decodeAudioData(rawAudioData, (buffer) => {
            resolve({buffer}); // or reject if failed
        });
    }).then(({buffer}) => buffer).catch(error => error)
};

function *fetchAudio({ url, audioContext }) {
    try {
        let rawAudioData = yield call(audioFileRequest, url);
        let buffer = yield call(decodeAudio, {rawAudioData, audioContext});
        acts.recivedAudioFile(buffer);
    }
    catch (error) {
        yield put(acts.errorFetchingAudioFile(error));
    }
}