Почему мой компонент React не отображает то, что я хочу, в foreach, а будет console.log массива? - PullRequest
0 голосов
/ 07 января 2020

Я слежу за онлайн-курсом о React и практикуюсь с API (swapi.co). Цель состоит в том, чтобы поиграться с API и создать приложение React, которое делает с ним все, что мы хотим.

Поэтому я пытаюсь создать приложение, которое имеет входные данные, и каждый раз, когда входные данные изменяются, оно выбирает соответствующий символ через API и отображает данные о персонаже. Одним из данных является название фильмов, в которых был персонаж, так что это массив, содержащий одну или несколько строк. Все идет хорошо, пока я не попробую l oop через этот массив для отображения. Он будет console.log всего массива, но не пропустит l oop через него с foreach.

Вот мой компонент результата:

class ResultPeople extends Component {
constructor() {
    super()
    this.state = {
        movieTitles: []
    }
}
getMovies(movies) {
    var movieTitleList = [];
    movies.forEach(element => {
        fetch(element)
        .then(resp => resp.json())
        .then(movieData => {
            movieTitleList.push(movieData.title);
        })
    });
    this.setState({movieTitles: movieTitleList});
    console.log('getMovies Done');
}
render() {
    const { resultdata } = this.props;
    const { name, films } = resultdata;
    return (
        <div className="result-characters text-white">
            <h2>{name}</h2>
            {films ? <button onClick={() => this.getMovies(films)}>See movies</button> : ''}
            {
                this.state.movieTitles ? <MovieList movies={this.state.movieTitles} /> : null
            }
        </div>
    );
}

}

И вот список mov ie:

const MovieList = ({ movies }) => {
return (
    <ul>
        {console.log(movies)}
        {
            movies.forEach(element => {
                return <li>{element}</li>;
            })
        }
    </ul>
);

}

Я понятия не имею, почему он так себя ведет. console.log (movies) работает хорошо (хотя в зависимости от того, сколько раз в нем записывается разное количество фильмов, возможно, из-за API?). Но foreach нет.

Где здесь ошибка? Спасибо!

Ответы [ 4 ]

2 голосов
/ 07 января 2020

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

Повторять фильмы с помощью Array.map() make вызов вызывает и возвращает обещания. Дождитесь завершения всех обещаний до sh, используя Promise.all(), а затем установите состояние.

Пример (не тестировался):

getMovies(movies) {
  Promise.all(movies.map(element =>
    fetch(element)
    .then(resp => resp.json())
    .then(movieData => movieData.title)
  )).then(movieTitles => this.setState({ movieTitles }))
}

Также используйте Array.map() в вашем компоненте , поскольку вы можете вернуться с Array.forEach().

Примечание: key должно быть уникальным. В этом примере я использую сам элемент, но если они не уникальны, вам нужно сгенерировать уникальный ключ.

const MovieList = ({ movies }) => (
  <ul>
  {
    movies.map(element => (
      <li key={element}>{element}</li>;
    ))
  }
  </ul>
);
1 голос
/ 07 января 2020

Это распространенная ошибка (я также поймал ее в ловушку несколько раз) - используйте .map!

Я имею в виду, что в компоненте MovieList есть forEach.

Также у вас есть начальный массив movieTitles: [], и проверка this.state.movieTitles ? всегда будет истинной. Установка нуля или удаление этой проверки в порядке.

0 голосов
/ 07 января 2020

Вы должны использовать Array.prototype.map(), а не Array.prototype.forEach()

> map () возвращает новый массив на основе предоставленного вами обратного вызова (что вам нужно)

{movies.map(element => (<li>{element}</li>)}

> forEach () запускает код в обратном вызове, но затем возвращает неопределенное значение.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

0 голосов
/ 07 января 2020

Вы делаете вызов в foreach l oop asyn c, а сама функция синхронна. Я, вероятно, написал бы ее как функцию карты, которая возвращает набор обещаний, которые при разрешении устанавливают состояние.

...
async getMovies(movies) {
    const promises = movies.map(async (element) => {
        const response = await fetch(element)
        const json = await response.json()

        return json.title
    })

    const titles = await Promise.all(promises)

    this.setState({movieTitles: titles});
}
...

Асин c / await - это просто более короткая форма, которую вы можете выполнить sh то же самое с then / catch. Я также добавил бы дополнительную обработку исключений и, возможно, возвращал бы ложное значение, когда он не может отфильтровать недопустимые заголовки mov ie.

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