Redux sagas在多次调度相同的id时仅获取一次

时间:2017-08-08 15:25:58

标签: redux-saga

我从我的API中获取用户并将其存储在我的状态中,因此我不必再次获取它。 问题是多个组件同时请求用户导致多个并发提取请求。

有没有一个好的模式可以避免这种情况?

这是我的传奇

function* watchUserRequests() {
    yield takeEvery(actionTypes.USER_REQUESTED, userRequested);
}

function* userRequested(action) {
    const {id} = action.payload;
    let user = yield select(state => state.users.all[id]);
    // cancel if user exists      
    if (user) return;
    user = yield call(userApi.get, id);
    yield put(userActions.userLoaded(id, banner));
}

操作

export function userRequested(id) {
    return {type: types.USER_REQUESTED, payload: {id}};
}

export function userLoaded(id, user) {
    return {type: types.USER_LOADED, payload: {id, user}};
}

2 个答案:

答案 0 :(得分:1)

这是我在另一个传奇中解决这个问题的方法。这里的“类型”可以忽略

  • 在ids对象中累积请求的ID:
  • 发送所有累积ID的调度操作
  • 去抖取50毫秒
  • 等待时......将新ID添加到ids对象
  • 等待时...取消获取任务以获得50新毫秒
  • 提交提取
  • 清除任务和ID

代码:

let ids = {};
let tasks = {};

function* watchCounterRequests() {
  yield takeEvery(actionTypes.COUNTER_REQUESTED, accumulate);
}

function* watchCounterFetchRequests() {
  yield takeEvery(actionTypes.COUNTER_FETCH_REQUESTED, counterFetchRequested);
}

function* accumulate(action) {
  const {id, type} = action.payload;
  if (!ids[type]) ids[type] = {};

  ids[type][id] = true;
  if (tasks[type]) {
    yield cancel(tasks[type]);
  }
  tasks[type] = yield fork(fetchCounters, type);
}

function* fetchCounters(type) {
  yield call(delay, 50);

  yield put({
    type: actionTypes.COUNTER_FETCH_REQUESTED,
    payload: {type: type, ids: Object.keys(ids[type])},
  });

  delete ids[type];
  delete tasks[type];
}

function* counterFetchRequested(action) {
  const {ids, type} = action.payload;
  let typeName = type + 'Ids';
  let req = {
    [typeName]: ids
  };
  yield put(counterActions.loadCounters(req));
}

export default [watchCounterRequests, watchCounterFetchRequests];

大部分内容来自:https://marmelab.com/blog/2016/10/18/using-redux-saga-to-deduplicate-and-group-actions.html

答案 1 :(得分:1)

它认为您正在寻找类似

import {
 take,
 fork,
 cancel,
} from 'redux-saga';

const takeLatestDeep = (pattern, identifier, fn, ...args) => fork(function* () {
  const tasks = {};

  while(true) {
    const action = yield take(pattern);
    const id = identifier(action);

    if (tasks[id]) {
      yield cancel(tasks[id]);
    } 

    tasks[id] = yield fork(fn, ...args.concat(action));
  }
}

您可以这样使用

yield takeLatestDeep(
   actionTypes.USER_REQUESTED,
   action => action.payload.id,
   fetchLegacyRecipientsSaga,
   ...args 
);