2016-11-18 7 views
1

Мой проект основан на React, перевождь, перевождь-сага, ES6, и я пытаюсь получить данные из этого API:Как получить данные по нескольким страницам?

http://api.dhsprogram.com/rest/dhs/data/BD,2000,2004,2007?&returnFields=CharacteristicLabel,Indicator,IndicatorId,Value&f=json

Как вы можете видеть, этот конкретный вызов API показывает данные с лимитом 100 данных на страницу с разметкой на 40 страниц.

В соответствии с этим ответом: http://userforum.dhsprogram.com/index.php?t=msg&th=2086&goto=9591&S=Google В нем говорится, что вы можете увеличить лимит до 3000data на страницу.

Однако, в некоторых случаях, я хотел бы сделать вызов API, который превышает этот предел, который означает, что я бы не получить все мои данные делают это так:

export function fetchMetaData(countryCode: string, surveyYears: string) { 
return (fetch('http://api.dhsprogram.com/rest/dhs/data/' + countryCode + ',' + surveyYears + '?returnFields=CharacteristicLabel,Indicator,IndicatorId,Value&f=json') 
    .then(response => response.json()) 
    .then(json => json.Data.map(survey => survey))) 
} 

Так что мой вопрос; каков наилучший способ получить все данные из этого API, учитывая, что я знаю общие страницы данных. Ответ в связи с форумом предполагает цикл через API. Однако я не могу найти правильное использование синтаксиса для этого.

Моя идея будет делать один вызов api, чтобы получить общее количество страниц. Затем сохраните это в состоянии, используя redux + redux-saga. Затем выполните новый запрос, отправляющий общие страницы в качестве параметра и выбирая это общее количество страниц раз. И делая это, я не могу понять синтаксис для хранения данных для каждой итерации.

+0

Несколько вопросов: 1. Зачем вам нужно экономить общее количество страниц в магазине redux? Вероятно, вы не должны инкапсулировать выборку всех данных в одно действие (используя несколько асинхронных выборок). 2. Вы скорее имели в виду «... отправку стартовой страницы в качестве параметра ...», правильно? 3. Что конкретно представляет собой ваша проблема, что вы пробовали до сих пор? Итерация по массивам? Агрегирование? Обработка нескольких асинхронных вызовов или обещаний? – matthias

+0

1. Сохранение общего количества страниц в магазине redux было всего лишь предложением моей собственной проблемы, и то, что вы предлагаете, более логично. 2. Исправить. 3. То, что я сделал до сих пор, - использовать саму саму сакс для обработки асинхронных выборок. Когда мои данные запроса компонента, отправив действие, мой наблюдатель в саге получает действие и запрашивает данные из вышеприведенной функции. То, что я получаю, - это данные с 1 страницы, которые я храню в корпусе действия и добавляю в мой редуктор. Моя проблема в том, что я не могу получить все данные с каждой страницы, используя вышеприведенную функцию. Есть ли разумный способ сделать это? @matthias –

+0

Хорошо, мы приближаемся к делу. Я никогда не использовал сага о редуксе и не знаю, предлагает ли этот lib специальный и предпочтительный способ решить эту проблему. Но я не думаю, что это не должно мешать вам решать вашу проблему обычным способом, используя обещания (или async/await) и функции, которые имеют дело со сборкой/отображением массивов и объектов. Если я правильно понял вас, вы ищете способ выполнить несколько асинхронных вызовов в один API, объединить собранные данные и передать их в хранилище/редуктор для создания нового состояния. Могу ли я спросить: Насколько вы знакомы с JavaScript в целом? – matthias

ответ

4

Возможное решение - идея состоит в том, чтобы сначала получить количество страниц, а затем сделать соответствующее количество вызовов API, отталкивая обещание от каждого вызова в массив. Затем мы ожидаем выполнения всех обещаний и сделаем что-то с возвращенными данными.

function fetchMetaData() { 
    let pagesRequired = 0; 

    fetch('apiUrlToGetPageNumber') 
    .then(resp = > { 
     const apiPromises = []; 
     pagesRequired = resp.data.pagesRequired; 

     for (let i=pagesRequired; i>0;i--) { 
      apiPromises.push(fetch('apiUrlToSpecificPage?page = ' + i)); 
     } 

     Promise.all(apiPromises) 
     .then(responses => { 
      const processedResponses = []; 
      responses.map(response => { 
       processedResponses.push(response); 
      } 

      // do something with processedResponses here 
     }); 
    } 
} 
+0

Большое спасибо!(Я поддержал ответ, но у меня меньше, чем на 15 пунктов). Однако, используя .reduce на обработанныхResponses; функция может напомнить, что prev определено. Но у меня есть идея, поэтому я попытаюсь понять это! –

+0

Хорошая точка на сокращении, я буду редактировать что-то, что работает. –

+0

Я был бы признателен, что =) –

0

Вот еще одно возможное решение с использованием async/await. Красота заключается в том, что подсчет total_pages является динамическим, так что, если он увеличивается, пока вы обрабатываете свой запрос, он будет убедиться, что вы все это получите.

async function fetchMetaData() { 
    let allData = []; 
    let morePagesAvailable = true; 
    let currentPage = 0; 

    while(morePagesAvailable) { 
    currentPage++; 
    const response = await fetch(`http://api.dhsprogram.com/rest/dhs/data?page=${currentPage}`) 
    let { data, total_pages } = await response.json(); 
    data.forEach(e => allData.unshift(e)); 
    morePagesAvailable = currentPage < total_pages; 
    } 

    return allData; 
}