Jammming step 95 : "default.search is not a function"

Hello everyone !

After have to quit code for a bit because of health issues, I am back with the Jammming Project.

It took me days to complete the project, and I am stuck at the very end: when I click on search button, I am told that ‘default.search is not a function’.

I checked other topics about this “not a function problem” and have already corrected some naming inconsistencies. But now I do not know where to check. I also have compared my work to some in the github repositories, without finding any notable difference.

Screenshot from 2023-03-23 16-30-44

Here is my code for App.js, SearchBar.js, Spotify.js:

App.js:

import React from "react"; import './App.css'; import SearchBar from "../SearchBar/SearchBar"; import PlayList from "../Playlist/Playlist"; import SearchResults from "../SearchResults/SearchResults"; import Spotify from "../util/Spotify"; class App extends React.Component { constructor(props){ super(props); this.state= { searchResults: [ ], playlistName:"K-POP Playlist", playlistTracks: [] }; this.addTrack = this.addTrack.bind(this); this.removeTrack = this.removeTrack.bind(this); this.updatePlaylistName = this.updatePLaylistName.bind(this); this.savePlaylist = this.savePlaylist.bind(this); this.search = this.search.bind(this); } addTrack(track) { let tracks = this.state.playlistTracks; if (tracks.find(savedTrack => savedTrack.id === track.id)){ return; } else { tracks.push(track); this.setState({playlistTracks: tracks}); {/*ne pas oublier les crochets dans la parentèses,sinon renvoie que pas défini. */} } }; removeTrack(track) { let tracks = this.state.playlistTracks; let trackToRemove = tracks.filter(function(savedTrack){ return tracks.indexOf(savedTrack.id) === track.id }) tracks.pop(trackToRemove); this.setState({playlistTracks: tracks}); }; updatePLaylistName(name) { let playlistName= this.state.playlistName; this.setState({playlistName: name}); } savePlaylist() { let tracks = this.state.playlistTracks; let trackURIs =tracks.map(track => track.uri); Spotify.savePlaylist(this.state.playlistName, trackURIs ).then(() => { this.setState({ playlistName:'New Playlist', playlistTracks: [] }) }); } search(userSearchTerm) { console.log(userSearchTerm); Spotify.search(userSearchTerm).then((searchResults) => { this.setState({searchResults:searchResults}); {/*On finit ici la promise commencée en Spotify.js*/} }); } render() { return ( <div> <h1>Ja<span className="highlight">mmm</span>ing</h1> <div className="App"> <SearchBar onSearch={this.search}/> <div className="App-playlist"> <SearchResults searchResults={this.state.searchResults} onAdd={this.addTrack} onRemove ={this.removeTrack}/> <PlayList playlistName={this.state.playlistName} onNameChange={this.updatePlaylistName} playlistTracks={this.state.playlistTracks} onSave={this.savePlaylist}/> </div> </div> </div> ); }; }; export default App;

SearchBar.js:

import React from "react"; import "./SearchBar.css"; class SearchBar extends React.Component { constructor(props) { super(props) ; this.state = {userSearchTerm: ''}; this.search = this.search.bind(this); this.handleTermChange = this.handleTermChange.bind(this); } search() { this.props.onSearch(this.state.userSearchTerm); {/*On prend le nom de la méthode dans le SearchBar, et non pas le nom de la valeur. */} } handleTermChange(event) { this.setState({userSearchTerm: event.target.value}); } render() { return( <div className="SearchBar"> <input placeholder="Enter A Song, Album, or Artist" onChange={this.handleTermChange}/> <button className="SearchButton" onClick={this.search}>SEARCH</button> </div> ); }; } export default SearchBar;

and finally Spotify.js:

import React from "react"; let userAccessToken; const client_ID = xxxx"; const redirect_URI = "http://localhost:3000"; class Spotify extends React.Component { getAccessToken() { if(userAccessToken) { console.log(userAccessToken); } let newUserAccessToken= window.location.href.match(/access_token=([^&]*)/); let expireDate =window.location.href.match(/expires_in=([^&]*)/); if(newUserAccessToken && expireDate) { userAccessToken = newUserAccessToken[1]; {/* Le premier de la liste qui peut matcher*/} let expiresIn = Number(expireDate[1]) ; {/*Retourne le expireDate sous format de nombre*/} window.setTimeout(() => userAccessToken = "", expiresIn *1000); window.history.pushState('Access Token', null, '/'); console.log(userAccessToken); } else{ const accessURL = `https://accounts.spotify.com/authorize?client_id=${client_ID}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirect_URI}`; window.location = accessURL; } } search(userSearchTerm){ const accessToken = Spotify.getAccessToken(); return fetch(`https://api.spotify.com/v1/search?type=track&q=${userSearchTerm}`, { headers: {Authorization: `Bearer ${accessToken}`} }).then(response => response.json() ).then(jsonResponse => { if(!jsonResponse.tracks) { console.log("No tracks were returned."); } return jsonResponse.tracks.items.map((track) => ( { id: track.id, name: track.name, artist: track.artists[0].name, album:track.album.name, uri: track.uri } )); }); }; savePlaylist(playlistName, trackURIs) { if(!playlistName || !trackURIs.length) { console.log("No Playlistname or no trackURIs."); } const accessToken = Spotify.getAccessToken(); const headers ={Authorization: `Bearer ${accessToken}`} ; let userID; let playlist_ID; return fetch(`https://api.spotify.com/v1/me`, {headers: headers} ).then(response => response.json() ).then(jsonResponse => { userID = jsonResponse.id; return fetch(`https://api.spotify.com/v1/users/${userID}/playlists`, { method: "POST", headers:headers, body: JSON.stringify({name:playlistName}) }).then(response => { if(response.ok) { return response.json(); } }).then(jsonResponse => {playlist_ID = jsonResponse.id; return fetch(`https://api.spotify.com/v1/users/${userID}/playlists/${playlist_ID}/tracks`, { method: 'POST', headers: headers, body: JSON.stringify({uris: trackURIs}) }) }) }) } } export default Spotify;

Some thoughts from me:

  • the console.log(userSearchTerm) is working, the function is also called.
  • I checked several times App.js and SearchBar.js, and also Spotify.js, but this latter one is more nested and more difficult to read, which tells me the error could come from here.
  • No other console.log in Spotify.search is returned, which make debugging difficult too → is the code not going there because of precedent problems ?

Thank you very much in advance for your help !

Not sure if that is all that is causing your problems, but you have a syntax error in your Spotify class: Methods in a Javascript class aren’t separated – neither with commas nor semicolons. You have a semicolon after the search method.

Aside: Better remove the API key in your code.

2 Likes

Thank you !

I changed it, but sadly the problem is still here :frowning:

Hello everyone,

after multiple checkings, I found the source of the problem:

  • in Spotify.js, I create a React Class Spotify, and NOT a variable. Thus, my way of calling the search method was not the right one.

Hope it can help others :slight_smile: