Выполнение вызова Axios в функции forEach для исправления объекта не распознается при рендеринге, несмотря на то, что он находится в состоянии - PullRequest
2 голосов
/ 10 июля 2019

Я пытаюсь изучить основы полнофункционального приложения React и столкнулся с очень странной проблемой, связанной с вызовами API.

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

Прямо сейчас консоль регистрирует массив, который получает компонент, и все данные присутствуют, однако каждое поле может быть отображено, кроме того, которое добавлено в цикл forEach.

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

// The API call

loadUserAndTrailers = () => {
        let trailers = []; 
        axios.get("http://localhost:5000/api/trailers")
        .then (res => {
            trailers = res.data;
        })
        .then (() => {          
            trailers.forEach(trailer => {

 axios.get(`http://localhost:5000/api/votes/user/${this.state.user.id}/${trailer.TrailerID}`)
                .then (res => {
                    const vote = res.data[0].Vote;
                    trailer.vote = vote;
                })
            })
        })
        .then (() => {
            this.setState({trailers: trailers});
        })
}

// The child component

const TrailerList = props => {

    console.log(props)

    const trailers = props.trailers.map(trailer => {
        return <div>{trailer.vote}</div>
    });

    return <div>{trailers}</div>;
};

// The return in the parent component

return (
  <div className="container">
    <div className="content">
      <h1>Trailers</h1>
      <div className="trailers">
      <TrailerList trailers={this.state.trailers}></TrailerList>
    </div>
  </div>
</div>
);

console.log (props) показывает мне законченный массив смассив объектов с этим значением ключа существует {голосования: 1}, но он ничего не отображает.Как это может быть?Я уже два дня бьюсь головой о стену, но я по общему признанию, плохо знаком с API и обещаниями.У меня сложилось впечатление, что обещание должно убедиться, что вызов завершен, прежде чем перейти к следующему шагу, и мое должным образом зарегистрированное состояние, кажется, подразумевает, что этот аспект кода функционирует, как ожидалось.

1 Ответ

3 голосов
/ 10 июля 2019

console.log (props) показывает мне законченный массив с массивом объектов с существующим значением этого ключа {voice: 1}, но он ничего не отображает. Как это может быть?

Timing. Вы запускаете цикл, делаете вызовы, затем не ждите , пока они не закончатся; ваш setState столкнется с незаполненными трейлерами, а через некоторое время их начнут заполнять аксиумы.

Что нужно знать о console.log (по крайней мере, в Chrome), так это то, что он также асинхронен при рендеринге объектов. Любые строки, которые вы регистрируете, будут зарегистрированы как есть; но рисование объектов требует времени, и к тому времени, когда браузер дойдет до него, он может рисовать объект, как он есть во время рисования , а не во время ведения журнала . Так что вы видите не то, что setState видел. См. Неужели консоль JavaScript в Chrome ленится при оценке массивов? Используйте JSON.stringify или выберите примитивные значения, чтобы записать, что на самом деле там.

Вам нужно убедиться, что then после цикла наступает после цикла (т. Е. Когда все результаты сделаны). Для этого нужно сделать две вещи.

1) Прямо сейчас, обещание axios в каждой итерации цикла (с его цепочкой then) отбрасывается - ничего не ждет его. Если мы вернем его и сделаем forEach в map, мы получим массив обещаний.

2) Чтобы дождаться всех обещаний в массиве, используйте Promise.all.

Итак ...

.then (() =>
  Promise.all(trailers.map(trailer =>
    axios.get(`${baseUrl}/${this.state.user.id}/${trailer.TrailerID}`)
    .then(res => {
      const vote = res.data[0].Vote;
      trailer.vote = vote;
    })
  ))
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...