Skip to main content

React Lifting Up State

Learning Objectives#

  • Learn how to lift state up from a component

React's data flow is unidirectional and data flows down: Data moves from parent components down. A parent component has no idea about the state of it's child components.

As we were updating our state of our individual products, the state in the parent component did not change.

Let's say we would want to make a list of favorite songs, that when a user clicks on an item, it gets a heart but also goes into the favorite songs list. We would need to move that information out of the SongList and into a FavoriteSongs component. There is no direct way to move this data from the SongList to the FavoriteSongscomponent - we have to move the data up into the shared parent component of SongList and FavoriteSongs and then dispatch the data to the FavoriteSongs.

If this seems, a bit unwieldy, especially if you have a lot of state to manage, a lot of people would agree. Therefore there are solutions to help, for example, there are other libraries like Redux that help manage state.

For now, we'll learn the basics of how to lift up state.

We also want to update our functionality of our onClick inside of the SongList, rather than toggle a true/false value, we want to take that item and add it to the App's state and then pass it down to the favorite songs.

Let's make a FavoriteSongs component. It's going to be very similar to our SongList, as a bonus, you could think about whether there would be a way to reuse our SongList or if it makes sense to keep them separate.

FavoriteSongs.js
class FavoriteSongs extends Component {  render() {    return (      <table>        <thead>          <tr>            <th>Song</th>            <th>Artist</th>            <th>Time</th>          </tr>        </thead>        <tbody>          {this.props.songs.map((song, index) => {            return (              <tr key={index}>                <td>{song.title}</td>                <td>{song.artist}</td>                <td>{song.time}</td>              </tr>            );          })}        </tbody>      </table>    );  }}

Now Let's import this new component: App.js

App.js
import React, { Component } from "react";import playlists from "./data.js";import SongList from "./components/SongList.js";import FavoriteSongs from "./components/FavoriteSongs.js";

Add an array to the state of the App component called lovedSongs

App.js#

App.js
this.state = {  playlists: playlists,  title: "",  artist: "",  time: "0:00",  lovedSongs: [],};

Let's make a function that will add to our lovedSongs in our App

App.js#

App.js
addLovedSong(song) {  this.setState({ lovedSongs: [song, ...this.state.lovedSongs] });}

and don't forget to bind this in the constructor

App.js
this.addLovedSong = this.addLovedSong.bind(this);

We have to pass this function down to our SongList

App.js
<SongList playlists={this.state.playlists} handleAdd={this.addLovedSong} />

Let's render this component(it'll be empty at first):

App.js#

App.js
<div className="playlists">  <SongList playlists={this.state.playlists} handleAdd={this.addLovedSong} />  <FavoriteSongs songs={this.state.lovedSongs} /></div>

Now we have to pass addLovedSong even further down into our Song component (this is called props drilling and is something that redux looks to solve)

SongList#

SongList.js
<Song song={song} key={index} handleAdd={this.props.handleAdd} />

Finally, we can call this function inside of our click event. However, we have two problems

  • we need to be able to pass an argument into the function. We can't do it onClick or else it will fire immediately
  • we already have another function being triggered on click

To solve this, we can wrap both functions in an anonymous function

Song#

Song.js
<tr  key={this.props.index}  onClick={() => {    this.props.handleAdd(this.props.song);    this.toggleLove();  }}>...</tr>;

Finally, let's add the songs in our list so that they render in our favorite songs component

Extra bonuses#

  • Whenever we click we add a song Fix it so that only loved songs can be added
  • We can add the same song multiple times - make it so that you can only add a song once
  • Make is so that you can remove a song from the favorites list