Я использую API-интерфейс spotify и извлекаю массив строк для установки в состояние для отображения в HTML через JSX.
Запись его на консоль показывает, что я получаю правильный массив, сохраненный в состоянии, но React никогда не выполняет рендеринг для их отображения. Если бы я установил снова после своих собственных значений, страница работает просто отлично. Может быть, это проблема с асинхронностью?
import React from 'react';
import Button from 'react-bootstrap/esm/Button';
import Spotify from 'spotify-web-api-js';
import Track from './Track';
import Api from '../Api.js'
export default class OtherPage extends React.Component{
constructor(props){
super(props);
this.state = {
artists:['artists']
};
this.getArtists = this.getArtists.bind(this);
}
async getArtists(){
let api = new Api();
let arr = await api.getTopArtists();
console.log('arr', arr);
this.setState({artists: arr});
console.log('new-arr', this.state.artists);
// this.setState({artists: ['noe', 'tow', 'tre']})
// console.log('new-new-arr', this.state.artists)
}
render(){
return(
<div>
<h1>My Spotify React App!</h1>
<div className="tracks-container" style={{maxHeight: 500, overflow: 'scroll', margin:50, marginTop:25}}>
{this.state.artists.map((artist) =>
<p>Artist: {artist}</p>
)}
<button onClick={() => this.getArtists()}>Get Top Artists</button>
</div>
</div>
);
};
}
Вот код для getTopArtists ()
import React from 'react';
import { Component } from 'react';
import Button from 'react-bootstrap/Button';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Redirect, BrowserRouter as Router, Route, Switch, useHistory } from 'react-router-dom';
class Api extends React.Component{
async getTopArtists(){
let arr = [];
let artists = await fetch("https://api.spotify.com/v1/me/top/artists", {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer '+ localStorage.getItem('access_token')
}
}
).then((response) => {
console.log(response.json().then(
(data) => data.items.forEach(item => arr.push(item.name))
)
)});
console.log(arr);
return arr;
}
}
export default Api;
2 ответа
Трудно сказать наверняка, но я бы попробовал два изменения:
Первый,
this.setState({artists: [...arr]});
Это заставляет создавать новый массив, на случай, если api.getTopArtists();
каким-то образом повторно использует тот же массив для своих результатов, что может привести к тому, что React не обнаружит изменения.
Во-вторых,
{this.state.artists.map((artist) =>
<p key={artist}>Artist: {artist}</p>
)}
Поскольку без ключа в списке, для реакции сложнее узнать, что изменилось в списке при изменении резервного массива. Вероятно, не проблема, но может быть.
В React есть специальный метод с именем componentDidMount () для выполнения вызовов внешних API.
Вызов внешнего API и setState впоследствии из метода componentDidMount () поможет достичь желаемого результата.
Рабочий пример с componentDidMount ():
export default class OtherPage extends React.Component{
constructor(props){
super(props)
this.state = {
artists:['artists']
}
}
componentDidMount() {
let api = new Api()
api.getTopArtists()
.then((arr) => {
this.setState({artists: arr})
})
}
render() {
return(
<div>
{this.state.artists.map((artist) =>
<p>Artist: {artist}</p>
)}
</div>
)
}
}
Дополнительная информация:
https://reactjs.org/docs/faq-ajax.html
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.