Can't figure out why React state is changing when I am not mutating any of the data or setting state anywhere

jcq5010 :

I am working with the Spotify API in React and I'm having trouble figuring out why my state is being mutated. Here is my code snippet:

curatePlaylist(playlist) {
        const workingPlaylist = { ...playlist };
        let curatedPlaylistNewTotal = workingPlaylist.level / 100 * workingPlaylist.tracks.length;
        const newPlaylist = [];
        for (let i = 0; i < curatedPlaylistNewTotal; i++) {
            let randomIndex = Math.floor(Math.random() * workingPlaylist.tracks.length);
            newPlaylist.push(workingPlaylist.tracks[randomIndex]);
            workingPlaylist.tracks.splice(randomIndex, 1);
        }
        return newPlaylist;
    }

    async createPlaylist() {
        const curatedChosenPlaylists = this.state.chosenPlaylists.map((p) => this.curatePlaylist(p));
        const newPlaylist = [].concat(...curatedChosenPlaylists);
        this.shuffle(newPlaylist);
        const response = await axios.post(
            `https://api.spotify.com/v1/users/${this.state.userData.id}/playlists`,
            { name: 'generatedPlaylist' },
            {
                headers: {
                    Authorization: 'Bearer ' + this.state.access_token
                }
            }
        );
        const newResponse = await axios.post(
            `https://api.spotify.com/v1/playlists/${response.data.id}/tracks`,
            { uris: this.formatURIs(newPlaylist) },
            { headers: { Authorization: 'Bearer ' + this.state.access_token } }
        );
    }

Quick walkthrough on what these 2 methods do:

  • A button onClick fires createPlaylist, which takes the chosenPlaylists array from state, maps over it, and for each one calls curatePlaylist which returns a curated playlist.
  • In curatePlaylist I am spreading the argument playlist into workingPlaylist, so I would think anything I then do to workingPlaylist wouldn't affect my state, but it does.
  • When I perform my for loop (which randomly chooses curatedPlaylistNewTotal # of tracks, each time splicing the chosen index from workingPlaylist), shouldn't this only affect workingPlaylist, and not anything in state? It appears as though my splice has affected my state but I can't figure out why. Can anyone offer an explanation?

UPDATE: Is the reason my state is being mutated because I am using the spread operator and then updating nested items of that copied array? If this is the case, is there an easy workaround?

Ali Nasserzadeh :

The problem is that you are accessing .tracks, it is correct that you did spread the playlist, but that only creates a shallow copy. This means that the member objects still reference the same objects. In your case tracks is still referencing your tracks in the state. You will have to spread the tracks to avoid this issue.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=383257&siteId=1