React Redux Saga活动频道取消

时间:2017-09-26 14:23:55

标签: reactjs redux redux-saga

有没有办法通过Redux Saga中的副作用来取消eventChannel

鉴于eventChannel连接到外部事件/数据流,在本例中为Firebase实时数据库"child_added"事件:

// action
const types = { SYNC: 'SYNC_TODOS' };
function syncTodos(todos) {
    return { types: types.SYNC, todos }
}

// saga
function todosChannel() {
  // firebase database ref
  const ref = firebase.database().ref('todos/');

  const channel = eventChannel(emit => {
    const callback = ref.on('child_added', (data) => {
      emit({ snapshot: data, value: data.val() })
    });

    // unsubscribe function
    return () => ref.off('child_added', callback);
  });

  return channel;
}

function* sync() {
  const channel = yield call(todosChannel);

  try {
    while (true) {
      const { value } = yield take(todosChannel);
      yield put(actions.syncTodos(value));
    }
  }
  finally {
    if(yield cancelled()) {
      channel.close();
    }
  }
}

export default function* rootSaga() {
  yield fork(sync);
}

是否有任何方法可以使用诸如fork()之类的副作用来监听取消事件频道并停止收听Firebase "child_added"事件/数据流的操作?或者这是否需要以某种方式保存对通道的引用并在通道引用本身上执行cancel()?

感谢您提供任何帮助。

2 个答案:

答案 0 :(得分:5)

你是说这个?

function* sync() {
  const channel = yield call(todosChannel);

  yield takeEvery(channel, function*({value}){
    yield put(actions.syncTodos(value))
  }

  yield take('CANCEL_WATCH')
  channel.close();
}

顺便说一下,takeEvery是帮手,不是效果。

答案 1 :(得分:1)

我不得不稍微修改可接受的答案方法,以捕捉频道中发出的错误。我也更喜欢在fork中处理cancel,而不是像接受的答案中那样处理fork。

function* sync() {
  const channel = yield call(todosChannel);

  yield fork(function* () {
    yield take('CANCEL_WATCH')
    channel.close();
  })

  try {
    while (true) {
      const { value } = yield take(channel)
      yield put(actions.syncTodos(value))
    }
  }
  catch (error) {
    yield put(actions.cancelWatch()) // to emit 'CANCEL_WATCH'
    yield put(actions.errorTodos(error))
  }
}