Я использую 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;
0
Froshiga 30 Июл 2020 в 00:43

2 ответа

Лучший ответ

Трудно сказать наверняка, но я бы попробовал два изменения:

Первый,

this.setState({artists: [...arr]});

Это заставляет создавать новый массив, на случай, если api.getTopArtists(); каким-то образом повторно использует тот же массив для своих результатов, что может привести к тому, что React не обнаружит изменения.

Во-вторых,

{this.state.artists.map((artist) => 
    <p key={artist}>Artist: {artist}</p>
)}

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

1
dave 29 Июл 2020 в 21:52

В 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

1
Gopinath 29 Июл 2020 в 22:02