Lab 6 - Communicating between components
Intro
In this lab you will be seeing how we can share stateful data between 2 components in a parent-child relationship.
Pre-requisites
You should have a running "hello world" application with the song list component.
1. Pass a stateful variable to a child component
-
In the song list component, create 2 local stateful javascript object variables called song1 and song2, each containing a title and artist name of a song.
-
Change the JSX in the song list component so that it passes a single property, a song, to the child component.
-
Amend the song component so that the information is still correctly displayed on the web page.
-
Create a button in the SongList component that will change the name of each song to a different one by the same artist.
-
Write a function to be executed when the button is clicked that changes both songs. (Hint: use the setter methods and the spread operator). Bind the function to the button's onClick event.
-
Check that when the button is clicked, the children are re-rendered
Click to view sample solution
const SongList = () => {
let [song1, setSong1] = useState({title : 'Last thing on my mind', artist: 'steps'});
let [song2, setSong2] = useState({title : 'If you\'re over me', artist: 'Years and years'});
const changeSong = () => {
setSong1({...song1, title : 'Something in your eyes'});
setSong2({...song2, title : 'King' })
}
return (
<div>
<ul>
<Song song={song1} />
<Song song={song2} />
</ul>
<button onClick={changeSong}>Change songs</button>
</div>
);
};
const Song = (props) => {
return (<li>{props.song.title} by {props.song.artist}</li>);
}
2. Update a parent's stateful variable from a child component
In this part of the lab we are going to be creating a facility to give each song a number of votes, and then we can vote separately for each song.
-
With the SongList component, adjust the 2 stateful song variables to include an extra field - the number of votes for a song.
-
Within the Songlist component, create 2 regular Javascript functions to increment the number of votes for each song (call these voteForSong1, voteForSong2)
-
Within the Songlist component, within the JSX that defines each instance of the Song component, add in an additional property called recordVote that points to the relevant voting function.
-
In the song object display the number of votes the song has received within the JSX.
-
In the song object, add a button for each song, which when pressed will increment the number of votes for that song
-
In the song object, bind the voting button to the relevant voting function in the parent object.
-
Check that when the voting buttons are clicked, the number of votes for each song is correctly recorded.
Click to view sample solution
import Song from './Song';
import {useState} from "react";
const SongList = () => {
let [song1, setSong1] = useState({title : 'Last thing on my mind', artist: 'steps', votes : 0});
let [song2, setSong2] = useState({title : 'If you\'re over me', artist: 'Years and years', votes : 0});
const addVote1 = () => {
setSong1({...song1, votes : song1.votes + 1});
}
const addVote2 = () => {
setSong2({...song2, votes : song2.votes + 1});
}
const changeSong = () => {
setSong1({...song1, title : 'Something in your eyes'});
setSong2({...song2, title : 'King' })
}
return (
<div>
<h2>Your favourite songs are:</h2>
<ul>
<Song song={song1} recordVote={addVote1}/>
<Song song={song2} recordVote={addVote2}/>
</ul>
<button onClick={changeSong}>Change songs</button>
</div>
);
};
export default SongList
const Song = (props) => {
const voteNow = () => {
props.recordVote();
}
return (<li>{props.song.title} by {props.song.artist} has {props.song.votes} votes. <button onClick={voteNow}>Vote for this song</button>
</li>);
}
export default Song