Changing One Item

Often the state is an array of objects, and one of them has to change. Here's the setlist of Night Trains, the songs they'll play, each with played:

const [songs, setSongs] = useState([
    { id: 1, title: "Last Train Home", played: false },
    { id: 2, title: "Midnight Express", played: false },
    { id: 3, title: "Steam and Smoke", played: false },
]);

To mark one song as played, you need a new array in which that song is a new object with played: true, and the other songs are as they were. That's map() with a condition:

function handlePlayed(id) {
    setSongs((songs) =>
        songs.map((song) =>
            song.id === id ? { ...song, played: true } : song,
        ),
    );
}

map() makes a new array of the same length. For each song, its arrow function returns what goes into the new array: for the song with that id, a copy with played: true, and for every other one, the song itself, unchanged. React gets a new array, renders, and the page shows the song as played.

What doesn't work is what you might write first: find the song and change it, song.played = true;. That changes an object inside the state, in place, just as push() did, so React gets no new value and the page doesn't change.

Now you have all three: spread to add an item to an array in state, filter() to remove one, and map() to change one.

Instructions

A click on Played marks its song as played. Write handlePlayed(id), which makes a new array with map() in which that song has played: true. The style crosses played songs out.

Make the button work both ways. On a played song, it says Undo, and a click marks the song as not played again. (!song.played is the opposite.)

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

Back

12/13

Next