Действия за изпращане на сага Redux от вътрешна карта в сага-действие

Имам API извиквания по следния начин:

  1. Извикване на main api, което ми дава масив от обекти.
  2. За всеки обект в масива трябва да извикам друг API асинхронно.
  3. Веднага след като извикването на под API за обекта приключи, актуализирайте неговите данни в хранилището на redux, което е масив (ofc), и го покажете.

Така че сценарият е списък, показващ елементи, които растат по динамичен начин.

Тъй като използвам redux-saga, трябва да изпратя втората част от вътре в redux-action. Опитах следния начин:

const response = yield call(get, 'endpoint')

const configHome = response.map(function* (ele) {
    const data = yield call(get, ele.SomeURI + '?someParameter=' + ele.someObject.id)
}))

Това не работи, тъй като картата не знае нищо за функциите на генератора. Така че опитах това:

const response = yield call(get, 'endpoint')

const configHome = yield all(response.map((ele) => {

     return call(get, paramsBuilder(undefined, ele.CategoryID))

}))

Но това ще блокира моя потребителски интерфейс от показване на налични данни, докато не завършат всички извиквания на под API.

Също така се опитах да направя отделна генераторна функция, която извиквам от вътрешната карта и извиквам нейната .next() функция, но проблемът тук отново е, че saga не контролира тази генераторна функция, така че ефектът на повикване не връща никаква стойност правилно.

Напълно блокиран в тази част. Ще се радвам на всяка помощ.


person Waleed    schedule 03.06.2021    source източник


Отговори (2)


Опитахте ли това, създадох пример, който може да помогне

import { put, takeLatest, all, call } from 'redux-saga/effects';
function* _fetchNews(id) {
  const data = yield fetch(
    `https://jsonplaceholder.typicode.com/todos/${id}`
  ).then(function(response) {
    const data = response.json();
    return data;
  });
  console.log(id);
  yield put({ type: 'NEWS_RECEIVED', data });
  return data;
}

function* _getData() {
  const json = yield fetch('https://jsonplaceholder.typicode.com/todos').then(
    response => response.json()
  );
  return json;
}

function* fetchNews() {
  const json = yield _getData();
  const configHome = json.map(ele => _fetchNews(ele.id));
  for (var item of configHome) {
    yield item;
  }
}

function* actionWatcher() {
  yield takeLatest('GET_NEWS', fetchNews);
}

export default function* rootSaga() {
  yield all([actionWatcher()]);
}
person Rahul Sharma    schedule 17.06.2021
comment
Трябва да попълним елементи на екрана веднага щом извикването на API приключи. Така че, например, ако има 10 извиквания на API, които се разрешават първо, ние ще ги покажем. - person Waleed; 17.06.2021
comment
@Waleed Проверете сега, актуализирах извадката. - person Rahul Sharma; 17.06.2021

yield all - генераторът е блокиран, докато всички ефекти бъдат решени или веднага щом някой бъде отхвърлен

Така че ще трябва да изпращате събития отделно за всеки подAPI

Да приемем, че имате 2 действия:

export const getMainApi =() => ({
  type: types.GET_MAIN_API,
});

export const getSubApi = endpoint => ({
  type: types.GET_SUB_API,
  endpoint,
});

Тогава вашите операции ще бъдат:

const get = endpoint => fetch(endpoint).then(response => response);

function* fetchMainApi(action) {
  try {
    const response = yield call(get, 'endpoint');
    for (let i = 0; i < response.length; i += 1) {
      // dispatch here all sub APIs
      yield put(
        getSubApi(
          response[i].SomeURI + '?someParameter=' + response[i].someObject.id,
        ),
      );
    }
  } catch (e) {
    console.log(e);
  }
}

function* fetchSubApi(action) {
  try {
    const response = yield call(get, action.endpoint);
    yield put({
      type: types.RECEIVE_SUB_API,
      response
    });
  } catch (e) {
    console.log(e);
  }
}

takeLatest(type.GET_MAIN_API, fetchMainApi)
takeEvery(types.GET_SUB_API, fetchSubApi)

Така че при успешно получаване на под API трябва да вмъкнете данни във вашето състояние вътре в редуктори.

Това е просто псевдо код.

person Observer    schedule 22.06.2021