2017-03-26 4 views
6

Da die "yield" -Anweisung innerhalb eines Callbacks nicht erlaubt ist, wie kann ich die "put" -Funktion von redux-saga innerhalb eines Callbacks verwenden?Wie man in redux-saga innerhalb eines Rückrufs "nachgibt"?

würde Ich mag den folgenden Rückruf haben:

function onDownloadFileProgress(progress) { 
    yield put({type: ACTIONS.S_PROGRESS, progress}) 
} 

Dies funktioniert nicht und endet in „unerwartetem Token“, denn Ausbeute in einer einfachen Funktion ist nicht erlaubt. Sonst kann ich keinen Callback als "Funktion *" weitergeben, die Ausbeute ermöglichen würde. ES6 scheint hier kaputt zu sein.

Ich habe gelesen, dass Redux-Saga bietet einige Funktionen namens "Kanäle", aber um ehrlich zu sein, ich habe es nicht bekommen. Ich habe einige Male über diese Kanäle und den Beispielcode gelesen, aber in allen Beispielen haben sie sehr schwierige und unterschiedliche Probleme gelöst, nicht meinen einfachen Fall und am Ende des Tages bin ich dort oben angekommen.

Kann mir jemand eine Lösung sagen, wie man mit diesem Problem umgehen kann?

Der ganze Kontext:

function onDownloadFileProgress(progress) { 
    yield put({type: ACTIONS.S_PROGRESS, progress}) 
} 

export function * loadFile(id) { 
    let url = `media/files/${id}`; 

    const tempFilename = RNFS.CachesDirectoryPath + '/' + id; 

    const download = RNFS.downloadFile({ 
    fromUrl: url,   
    toFile: tempFilename, 
    background: false, 
    progressDivider: 10, 
    progress: onDownloadFileProgress, 
    }) 

    yield download.promise; 

} 
+0

Es ist nicht erlaubt <-> Sie können nicht – Bergi

+0

was wollen Sie damit sagen? macht es einen Unterschied? – delete

Antwort

10

Eine mögliche Lösung, wie Sie bereits erwähnt, ist channels zu verwenden. Hier ist ein Beispiel, das in Ihrem Fall funktionieren soll:

import { channel } from 'redux-saga' 
import { put, take } from 'redux-saga/effects' 

const downloadFileChannel = channel() 

export function* loadFile(id) { 
    ... 
    const download = RNFS.downloadFile({ 
    ... 
    // push `S_PROGRESS` action into channel on each progress event 
    progress: (progress) => downloadFileChannel.put({ 
     type: ACTIONS.S_PROGRESS, 
     progress, 
    }), 
    }) 
    ... 
} 

export function* watchDownloadFileChannel() { 
    while (true) { 
    const action = yield take(downloadFileChannel) 
    yield put(action) 
    } 
} 

Die Idee dabei ist, dass wir eine S_PROGRESS Aktion auf dem Kanal für jeden Fortschritt Ereignis schieben, die von RNFS.downloadFile emittiert wird.

Wir müssen auch eine andere Saga-Funktion starten, die jede gedrückte Aktion in einer while Schleife (watchDownloadFileChannel) abhört. Jedes Mal, wenn eine Aktion aus dem Kanal ausgeführt wird, verwenden wir das normale yield put, um redux-saga mitzuteilen, dass diese Aktion ausgelöst werden soll.

Ich hoffe, diese Antwort wird Ihnen helfen.

+0

Funktioniert gut! Vielen Dank! – delete

+0

Dies scheint eine Lösung für mein ähnliches Problem, aber ich bekomme Kanalpufferüberläufe. Wie hast du den 'watchDownloadFileChannel' mit der sagaMiddleware verbunden? – dougajmcdonald

1

Ich bin diese Woche in eine ähnliche Situation geraten.

Meine Lösung war, eine Nachricht innerhalb des Rückrufs aufzurufen und das Ergebnis zu übergeben.

Ich war Umgang mit Datei-Uploads wollte so einen readAsArrayBuffer() Anruf zu tun, zunächst in meiner Saga etwas wie folgt aus:

function* uploadImageAttempt(action) { 
    const reader = new FileReader(); 

    reader.addEventListener('loadend', (e) => { 
    const loadedImage = reader.result; 
    yield put(Actions.uploadImage(loadedImage)); // this errors, yield is not allowed 
    }); 

    reader.readAsArrayBuffer(this.refs[fieldName].files[0]); 
} 

Wie ich um diese bekam, war durch die readAsArrayBuffer() in meiner Komponente tut, dann nennen verbunden Dispatch-Funktion:

// in my file-uploader component 
handleFileUpload(e, fieldName) { 
    e.preventDefault(); 

    const reader = new FileReader(); 

    reader.addEventListener('loadend', (e) => { 
    const loadedImage = reader.result; 
    this.props.uploadFile(
     this.constructDataObject(), 
     this.refs[fieldName].files[0], 
     loadedImage 
    ); 
    }); 

    reader.readAsArrayBuffer(this.refs[fieldName].files[0]); 

} 

... 

const mapDispatchToProps = (dispatch) => { 
    return { 
    uploadFile: (data, file, loadedImage) => { 
     dispatch(Actions.uploadFile(data, file, loadedImage)) 
    } 
    } 
} 

Hoffnung, die

0

Neben mit channel hilft als @ Alex vorschlagen, man könnte auch in Betracht ziehen, call von zu verwenden. Der call Effekt hat eine Funktion oder Promise.

import { call } from 'redux-saga/effects'; 
 

 
// ... 
 

 
yield call(download.promise);

Verwandte Themen