ReactJS中作用域与OOP问题:函数调用时this未定义
Hey there! Let's break down why you're hitting that Unhandled Rejection (TypeError): this is undefined error and get it fixed right away.
Why This Happens
The root issue comes down to how this works in JavaScript regular functions. When you pass a standard function() to the .then() method in your getPlaylists function, that callback creates its own this context—one that doesn't point to your React component instance. Since React runs in strict mode by default, this inner this ends up being undefined, so calling this.getPlaylistTracks() throws an error.
3 Simple Fixes
Let's walk through the most common solutions, starting with the cleanest modern approach:
1. Use Arrow Functions for the Promise Callback
Arrow functions don't create their own this—they inherit the this from the outer scope (your component instance). Just swap out the regular function for an arrow function in your .then():
getPlaylists() { spotifyApi.getUserPlaylists().then( (data) => { // Changed to arrow function here var playlistArray = []; for(let i = 0; i < data.items.length; i++) { var tracksURL = data.items[i].tracks.href.slice(37,59); var playlist = new PlaylistObj(data.items[i].name, data.items[i].tracks.total, tracksURL); this.getPlaylistTracks(tracksURL); // Now `this` correctly points to your component playlistArray[i] = playlist; } return playlistArray; }, (err) => { // Optional: Swap this error callback to arrow function too console.error(err); } ); }
2. Bind this to the Callback Function
If you prefer sticking with regular functions, you can explicitly bind the component's this to the callback using .bind(this):
getPlaylists() { spotifyApi.getUserPlaylists().then( function (data) { var playlistArray = []; for(let i = 0; i < data.items.length; i++) { var tracksURL = data.items[i].tracks.href.slice(37,59); var playlist = new PlaylistObj(data.items[i].name, data.items[i].tracks.total, tracksURL); this.getPlaylistTracks(tracksURL); playlistArray[i] = playlist; } return playlistArray; }.bind(this), // Bind component's `this` to the callback function (err) { console.error(err); } ); }
3. Save this to a Variable Before the Promise
A reliable old-school trick is to store the component's this in a variable (like that) before entering the Promise chain, then use that variable inside the callback:
getPlaylists() { const that = this; // Save component's `this` to a variable spotifyApi.getUserPlaylists().then( function (data) { var playlistArray = []; for(let i = 0; i < data.items.length; i++) { var tracksURL = data.items[i].tracks.href.slice(37,59); var playlist = new PlaylistObj(data.items[i].name, data.items[i].tracks.total, tracksURL); that.getPlaylistTracks(tracksURL); // Use `that` instead of `this` playlistArray[i] = playlist; } return playlistArray; }, function (err) { console.error(err); } ); }
Bonus: Prevent Future this Issues
To avoid similar problems elsewhere in your component, make sure your getPlaylists and getPlaylistTracks methods are bound to the component instance. Here are two easy ways:
Option A: Bind in the Constructor
constructor(props) { super(props); // Bind methods to component instance this.getPlaylists = this.getPlaylists.bind(this); this.getPlaylistTracks = this.getPlaylistTracks.bind(this); }
Option B: Define Methods as Arrow Functions
This is a cleaner modern approach—arrow functions for class methods automatically bind this to the component:
// Define methods as arrow functions getPlaylistTracks = (tracksURL) => { spotifyApi.getPlaylist(tracksURL).then( (data) => { console.log(data); }, (err) => { console.error(err); } ); } getPlaylists = () => { spotifyApi.getUserPlaylists().then( (data) => { var playlistArray = []; for(let i = 0; i < data.items.length; i++) { var tracksURL = data.items[i].tracks.href.slice(37,59); var playlist = new PlaylistObj(data.items[i].name, data.items[i].tracks.total, tracksURL); this.getPlaylistTracks(tracksURL); playlistArray[i] = playlist; } return playlistArray; }, (err) => { console.error(err); } ); }
内容的提问来源于stack exchange,提问作者mullano

