简体   繁体   English

onClick 没有在 React 中正确触发函数

[英]onClick is not firing the function correctly in React

So I have this button:所以我有这个按钮:

<button onClick={this.setRecommendations}>
   log into Spotify
</button>

Calls this function:调用这个函数:

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

Which calls this function:其中调用此函数:

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;
}

Which calls another function and another function ultimately one of the first things it does is call getAccessToken :它调用另一个函数和另一个函数,最终它做的第一件事就是调用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;
    }
  },

The functions ultimately work but you have to click the button twice.这些功能最终会起作用,但您必须单击该按钮两次。 Last night I tried putting some console.log() s to see what was happening and then I realized that this.setRecommendation doesn't seem like it is being called until the second click.昨晚我尝试放置一些console.log()来查看发生了什么,然后我意识到this.setRecommendation似乎直到第二次点击才被调用。 but the button still took you to the login screen so somehow it was getting to getAccessToken :但该按钮仍将您带到登录屏幕,因此不知何故它正在获取getAccessToken

I even tried:我什至试过:

setRecommendations(){
    console.log("you pushed the button");
    recommendations().then(recs => {
      this.setState({recommendations: recs});
    });
  }

And "you pushed the button" would still not be console logged until the second click, but again it would take you to the login, so I created a second function login() an all it does is call getAccessToken() :并且“你按下按钮”在第二次点击之前仍然不会被控制台记录,但它会再次带你登录,所以我创建了第二个函数login() ,它所做的只是调用getAccessToken()

  login(){
    Spotify.getAccessToken();
  }

So I have two buttons, one calls this.login the other calls this.setRecommendations when I click this.login and then this.setRecommendations it works as you expected, populates the components nicely.所以我有两个按钮,一个调用this.login另一个调用this.setRecommendations当我点击this.login然后this.setRecommendations它按你的预期工作,很好地填充组件。

But I would still like this to be one click.但我仍然希望这是一键式的。 I tried:我试过:

  <button onClick={() => {
                          this.login();
                          this.setRecommendations();}}>
          log into Spotify
          </button>

But that doesn't work it still calls this.login() and doesn't seem to call this.setRecommendations() until once again the second click.但这不起作用它仍然调用this.login()并且似乎直到再次单击第二次才调用this.setRecommendations()

this is my App Component这是我的应用程序组件

import React from 'react';
import './App.css';
import {Spotify, recommendations} from '../../utils/Spotify';
import RecommendationButton from '../RecommendationButton/RecommendationButton';
import Playlist from '../Playlist/Playlist';
import Graphs from '../Graphs/Graphs'
import RecommendationResults from '../RecommendationResults/RecommendationResults';


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.login = this.login.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});
    });
  }

  login(){
    Spotify.getAccessToken();
  }

  setRecommendations(){
    recommendations().then(recs => {
      console.log(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() {
    return (
      <div>
        <h1>Spotify Recommendations</h1>
        <div className="App">
          <button onClick={this.login}>
          log into Spotify
          </button>
          <RecommendationButton onPush={this.setRecommendations} />
          <Graphs data={this.state.album_count} margins={this.state.topAlbums} graphID={"topAlbums"} />
          <div className="Graphs">
            <Graphs data={this.state.artist_count} margins={this.state.topArtist} graphID={"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>
    );
  }
}


export default App;

Do you need the Access Token before you are able to get the recommendations?在获得建议之前,您是否需要访问令牌?

It may be the case that on the first click the program does not yet have the access token needed to get the recommendations and that's why it takes two clicks, because there is a pause for it to get the access token between the two clicks.可能的情况是,在第一次点击时,程序还没有获取推荐所需的访问令牌,这就是为什么它需要点击两次,因为在两次点击之间有一个暂停来获取访问令牌。 This may be caused by the following line in getAccessToken :这可能是由getAccessToken的以下行引起的:

window.setTimeout(() => accessToken = '', expiresIn * 1000);

You could try having getAccessToken() return a promise with the resolve value being the access token.您可以尝试让getAccessToken()返回一个承诺,解析值是访问令牌。 And then in your login function call getAccessToken and .then() setRecommendations .然后在您的登录函数中调用getAccessTokensetRecommendations .then() setRecommendations

In your JSX you would just have onClick={this.login} .在您的 JSX 中,您将只有onClick={this.login}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM