「yield」ステートメントはコールバック内では許可されないため、コールバック内でredux-sagaの「put」機能を使用するにはどうすればよいですか?
次のコールバックを希望します。
function onDownloadFileProgress(progress) {
yield put({type: ACTIONS.S_PROGRESS, progress})
}
yieldは単純な関数では使用できないため、これは機能せず、「予期しないトークン」になります。そうしないと、コールバックを "function *"として渡すことができません。 ES6はここで壊れているようです。
Redux-sagaが "channels"と呼ばれるいくつかの機能を提供していることを読んだことがありますが、正直なところ、わかりませんでした。私はこれらのチャネルとサンプルコードについて何度か読みましたが、すべての例で、非常に困難で異なる問題を解決しました。私の単純なケースではなく、結局私はそこにたどり着きました。
誰かがこの問題の対処方法を教えてくれますか?
全体のコンテキスト:
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;
}
すでに述べたように、1つの可能な解決策はchannels
を使用することです。これはあなたのケースでうまくいくはずの例です:
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)
}
}
ここでの考え方は、S_PROGRESS
から発行される進行状況イベントごとに、チャネルでRNFS.downloadFile
アクションをプッシュすることです。
また、while
ループ(watchDownloadFileChannel
)でプッシュされた各アクションをリッスンする別のsaga関数を開始する必要があります。チャネルからアクションが実行されるたびに、通常のyield put
を使用して、このアクションをディスパッチする必要があることをredux-saga
に通知します。
この回答がお役に立てば幸いです。
今週も同じような状況に陥りました。
私の解決策は、コールバック内でディスパッチを呼び出し、結果を渡すことでした。
私はファイルのアップロードを処理していたので、readAsArrayBuffer()
呼び出しをしたいと思っていました。
_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]);
}
_
これを回避する方法は、コンポーネントでreadAsArrayBuffer()
を実行してから、接続されたディスパッチ関数を呼び出すことでした。
_// 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))
}
}
}
_
それが役に立てば幸い
@Alexが示唆するようにchannel
を使用する以外に、'redux-saga/effects'
のcall
の使用を検討することもできます。 call
効果は関数またはPromise
を受け取ります。
import { call } from 'redux-saga/effects';
// ...
yield call(download.promise);