我必须单击按钮两次才能使状态在 React 中正确呈现

IT技术 javascript reactjs
2021-05-17 16:29:51

我正在使用 React 并且我有一个按钮可以设置状态

<button class="button" onClick={this.setRecommendations}>
            Log Into Spotify
</button>

这称为功能

setRecommendations(){
    recommendations().then(recs => {
      this.setState({recommendations: recs});
    });
  }

这会更新此状态,recommendations: [],因此当我单击按钮时,我会等待一段时间,但没有任何react,但是无论我再次单击按钮的那一刻等待多久,结果都开始显示。

我知道 setState 是异步的,但是这段代码模仿了一个类似的功能,只需单击一下即可更即时地显示结果,我可以做些什么来使其一键运行?

*******更新更多代码*******

这是我的应用程序

  class App extends React.Component {
  //constructor
  constructor(props) {
    super(props);

    this.state = {
      searchResults: [],
      recommendations: [],
      playlistName: 'New Playlist',
      playlistTracks: [],
      topAlbums: ["Cats", "Wicked", "Heathers", "Charli", "Little Mermaind"],
      album_count: [10, 20, 25, 30, 35],
      topArtist: ["Dua Lipa", "Sierra Boggess", "Barrett Wilbert Reed", "Charli XCX", "Jessica Klean"],
      artist_count: [5, 10, 25, 35, 55],
      topGenre: ["classical", "broadway", "pop", "punk", "hip-hop"],
      genre_count: [50, 25, 5, 13, 7],
      popRange: ["0-20", "21-40", "41-60", "61-80", "81-100"],
      pop_count: [20, 40, 60, 40, 20]
    };
    this.search = this.search.bind(this);
    this.setRecommendations = this.setRecommendations.bind(this);
    this.addTrack = this.addTrack.bind(this);
    this.removeTrack = this.removeTrack.bind(this);
    this.updatePlaylistName = this.updatePlaylistName.bind(this);
    this.savePlaylist = this.savePlaylist.bind(this);
  }

  search(term) {
    Spotify.search(term).then(searchResults => {
      this.setState({searchResults: searchResults});
    });
  }

  setRecommendations(){
    recommendations().then(recs => {
      this.setState({recommendations: recs});
    });
  }

  //addTracks
  addTrack(track) {
    let tracks = this.state.playlistTracks;
    if (tracks.find(savedTrack => savedTrack.id === track.id)) {
      return;
    }

    tracks.push(track);
    this.setState({playlistTracks: tracks});
  }

  //removeTracks
  removeTrack(track) {
    let tracks = this.state.playlistTracks;
    tracks = tracks.filter(currentTrack => currentTrack.id !== track.id);

    this.setState({playlistTracks: tracks});
  }

  //updatePlaylistName
  updatePlaylistName(name) {
    this.setState({playlistName: name});
  }

  //savePlaylist
  savePlaylist() {
    const trackUris = this.state.playlistTracks.map(track => track.uri);
    Spotify.savePlaylist(this.state.playlistName, trackUris).then(() => {
      this.setState({
        playlistName: 'New Playlist',
        playlistTracks: []
      });
    });
  }

  //This what we will see
  render() {
    //this.recommendations()
    return (
      <div>
        <h1>Spotify Recommendations</h1>
        <div className="App">
          <button class="button" onClick={this.setRecommendations}>
            Log Into Spotify
          </button>
          <Graphs data={this.state.album_count} margin={this.state.topAlbums} />
          <div className="Graphs">
            <Graphs data={this.state.artist_count} margin={this.state.topArtist} />
          </div>
          <p> below are some recommendations based on your listening history </p>
          <div className="App-playlist">
            <RecommendationResults recommendationResults={this.state.recommendations}
                           onAdd={this.addTrack} />

            <Playlist playlistName={this.state.playlistName}
                      playlistTracks={this.state.playlistTracks}
                      onNameChange={this.updatePlaylistName}
                      onRemove={this.removeTrack}
                      onSave={this.savePlaylist} />
          </div>
        </div>
      </div>
    );
  }
}

单击按钮后,它会显示建议

<RecommendationResults recommendationResults={this.state.recommendations}
                           onAdd={this.addTrack} />

它调用这个组件

class RecommendationResults extends React.Component {
  render() {
    return (
      <div className="RecommendationResults">
        <h2>Recommendations</h2>
        <TrackList tracks={this.props.recommendationResults} onAdd={this.props.onAdd} />
      </div>
    );
  }
}

它调用另一个组件

class TrackList extends React.Component {
  render() {
    return (
      <div className="TrackList">
        {
          this.props.tracks.map(track => {
            return <Track track={track}
                          key={track.id}
                          onAdd={this.props.onAdd}
                          isRemoval={this.props.isRemoval}
                          onRemove={this.props.onRemove} />
          })
        }
      </div>
    );
  }
}

这是函数 setRecommendations 调用

//get recommendations based off song history
export async function recommendations(){
  const unique = await findUnique();
  const recommendations = [];
  for(var index = 0; index < unique.length; index++){
    var trackURI = (unique[index].uri).slice(14, (unique[index].uri).length);
    var rec = await Spotify.recommendations(trackURI, unique[index].pop);
    for(var i=0; i<rec.length; i++){
      recommendations.push(rec[i]);
    }
  }
  const uniqueRec = getUnique(recommendations);
  return await uniqueRec;
}

这个函数是问题所在,else 子句没有返回任何内容,因此如果这是第一次调用它,直到第二次才会返回任何内容。

//getAccessToken
  getAccessToken() {
    if (accessToken) {
      return accessToken;
    }
    const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
    const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
    if (accessTokenMatch && expiresInMatch) {
      accessToken = accessTokenMatch[1];
      const expiresIn = Number(expiresInMatch[1]);
      window.setTimeout(() => accessToken = '', expiresIn * 1000);
      window.history.pushState('Access Token', null, '/'); // This clears the parameters, allowing us to grab a new access token when it expires.
      return accessToken;
    } else {
      const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=${scopes.join("%20")}&redirect_uri=${redirectUri}`;
      window.location = accessUrl;
    }
  },
1个回答

问题是getAccessToken()在调用后需要再次window.location调用。决定getAccessToken()在 else 块之后调用window.location就足够了,从而解决了这个问题。