Как "yield put" в redux-saga в рамках обратного вызова?

поскольку оператор " yield "не разрешен в обратном вызове, как я могу использовать функцию" put " redux-saga в обратном вызове?

Я хотел бы иметь следующий обратный вызов:

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

это не работает и заканчивается "неожиданно", потому что доходность не допускается в простой функции. В противном случае я не могу передать обратный вызов как "

3 ответов


одним из возможных решений, как вы уже упоминали, является использование 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). Каждый раз, когда действие было предпринято с канала, мы используем normal 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))
    }
  }
}

надеюсь, что это поможет


рядом с помощью channel как предлагает @Alex, можно также рассмотреть возможность использования call С 'redux-saga/effects'. The call эффект взять функцию или Promise.

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

// ...

yield call(download.promise);