Вложенные вызовы API в React Redux - PullRequest
0 голосов
/ 29 октября 2018

Мне трудно понять, что происходит (и не происходит) в моем создателе действий.

Мне нужно позвонить на одну конечную точку API, получить идентификаторы и имена всех возвращаемых элементов, а затем для каждого из этих идентификаторов сделать еще один вызов. Я хочу сохранить результат последнего вызова и идентификаторы / имена из первого вызова в объекте и отправить его.

{
  category: name //name of category
  subcategory: [] //array of categories in the category above. 
}

Прямо сейчас, мой редуктор в итоге имеет то, что я хочу, но когда я пытаюсь зарегистрировать эту конкретную опору в компоненте, она пуста. (ниже я использую OpenSocialAPI или osapi. Это просто базовая оболочка для запроса AJAX. Позволяет мне не выполнять аутентификацию, поскольку видит, что я уже аутентифицирован.)

export function fetchCategories(id){
  let categories = []
  return function(dispatch){
    dispatch(requestCategories(id))
    return osapi.core.get({
      v: "v3",
      href: "/places/" + id + "/places"
    }).execute(function(response) {
      response.content.list.forEach(function(category) {
        osapi.core.get({
          v: "v3",
          href: "/places/" + category.id+ "/categories"
        }).execute(function(response) {
          categories.push({
            category: category.name,
            subcategories: response.content.list.map(category => category.name)
          })
        })
      })

    console.log("Category response: ", categories)
    dispatch(receiveCategories(id, categories))
    })
  }
}
export function receiveCategories(id,array){
  return {
    type: RECEIVE_CATEGORIES,
    id,
    categories: array,
    recievedAt: new Date(Date.now()),
    isFetching: false
  }
}

И в моем приложении я отправляю создателя действий в componentDidMount

  componentDidMount() {
    const { dispatch } = this.props
    dispatch(fetchCategoriesIfNeeded(id))
  }

Прямо сейчас, когда я консоль входа в мой компонент категории и в выполнении выше, он пуст. Но, глядя на мое состояние в моем логгере, когда recieveCategories завершен, у меня есть массив объектов, которые я хочу

[{category:..., 
  subcategories:[...]
 },
 {category:..., 
  subcategories:[...]
 }]

Я подозреваю, что это из-за чего-то асинхронного, но я не уверен, что делать дальше.

Я попытался создать свою собственную оболочку для вызова, основанного на обещаниях, но у меня были похожие проблемы, возможно, даже больше, потому что я не уверен, что мне нужно разрешение (ответ).

function httpService(path){
   return new Promise(function(resolve, reject){
          osapi.core.get({
              v: 'v3',
              href: path
          }).execute(function(response, error){
              if(error){
                  return reject(new Error("Error: ", error))
              }
              resolve(response)
          })  
        })
}
export function fetchCategories(spaceId) {
  let categories = []
  return function(dispatch) {
    dispatch(requestCategories(id))
    return httpService("/places/" + id + "/places")
      .then(function(response) {
        response.content.list.forEach(function(category) {
          fetchSubCategories("/places/" + category.id + "/categories")
            .then(function(response) {
              categories.push({
                category: category.name,
                subcategories: response
              })
            })
        })
        console.log("CATEGORIES: ", categories)
        dispatch(receiveCategories(id, categories))
      })
  }
}
function fetchSubCategories(url){
  return httpService(url)
  .then(function(response){
    return response.content.list.map(category => category.name)
  })
}

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

Мне удалось найти только 1 другой вопрос с похожим вариантом использования, но они используют bluebird или что-то подобное. Я бы очень хотел оставить это без чего-либо лишнего, кроме Redux.

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Я думаю, osapi.core.get - это какая-то библиотека выборок, основанная на обещаниях? И .execute вызывается, когда получится успешно?

Если это так, то вам не хватает того, что вы не дожидаетесь завершения всех асинхронных вызовов.

Я собираюсь показать решение, основанное на общих fetch и нативных обещаниях, чтобы вы могли понять решение и принять его на основе ваших конкретных библиотек.

const promises = [];
response.content.list.forEach(function(category) {
    const promise = fetch("/places/" + category.id+ "/categories");
    promises.push(promise);
})

Promise.all(promises).then(responses => {        
    categories = responses.map(response => ({/* do your object mapping here */}))
    // now you can dispatch with all received categories
    dispatch(receiveCategories(id, categories))
}); 

Кроме того, вы используете ту же переменную в своих вложенных функциях - хотя это может сработать и компьютеры могут это понять, любому человеку будет очень сложно определить, какой response принадлежит какой области. Поэтому вы можете еще раз взглянуть на имена переменных.

0 голосов
/ 29 октября 2018

Похоже, вам просто нужно отправить ваши категории внутри вашего .execute() обратного вызова, а не вне его. Вы делаете osapi.core.get().execute((response) =>, но затем за пределами этого execute обратного вызова, вы отправляете receiveCategories, который будет выполняться задолго до разрешения вашего Promise, и отправляете пустой массив, который вы инициализируете.

Вам также нужно использовать Promise.all, чтобы получить ответ на все ваши вложенные GET запросы.

Нет также никаких причин держать мутирующий массив вокруг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...