In React, our UI is a function of state (and props). In this lesson, we'll create some internal state and pass some props into a class component and use them together to render some UI in the class component's render
method.
Andy Van Slaars: [0:00] To start making this component more interactive, we're going to need to get some data into it and then internally manage some state. Let's start by going to app.js and passing our cards in as a prop we'll call cards. Just like we pass cards into cardList will pass cards into practice as a prop. We can save that.
[0:20] Back in our practice component, let's start adding some state. Then we'll see how we can use the state and the props together. At the top of my class, before the render method, I'm going to add a property on this class called state. State is going to be an object.
[0:35] Inside state, I'm going to give it a key we'll call currentIndex. I'm going to set the initial value on that to zero. This is a piece of state in my component that has a currentIndex. This will change over time.
[0:46] Now that we have a piece of state and we have a prop being passed in, let's go down to render and use those. I'm going to start at the top of render. I'm going to destructure my props and my state. I'll do a const cards. That's going to come off of this.props because we have to reference props and state off of this in a class component.
[1:09] Then I'm going to do the same thing on the next line for currentIndex. That will come from this.state. This is just going to help us avoid typing this.state, our key name or this.props, our key name throughout our JSX. It'll keep that a little bit cleaner.
[1:26] Now let's use our props and our state value in our render. I'm going to scroll down a bit. I'm going to take this div that's showing our progress. Right now, it's just hard-coded. I'm going to replace one. This is going to show the number of the card that you're currently on. It'll be our currentIndex.
[1:44] We want this to be more user-friendly. Instead of showing zero for the first index, we'll just add one. You'll be on card one when it's indexed zero. Then we want that to be out of our total number of cards. I'll replace this hard-coded five with cards.length. Let's save that.
[2:03] I want to just go to our browser and make sure now we're seeing one of three. It's not the hard-coded value anymore. It's using the actual length of our deck of cards. I'll come back. I want to update this hard-coded term with the term from our actual card based on the index.
[2:21] I'll come back up to the top here. I'm going to define a constant. I'm going to call it currentCard. That's going to equal cards of currentIndex. In this case, for now it'll just give us the first card. Now I can come down here. I can reference currentCard.term. We'll save that. We'll go back.
[2:51] When the browser reloads, we're going to get this error, "Can't read property term of undefined." Let's look at our code and see what's happening here. Cards is being passed down from our app component. That's being fetched through an API call.
[3:04] In the initial render, cards is just going to be the default value, which is an empty array. We're getting an empty array here for cards. The other thing that could happen is that cards could not be passed in at all and that could be undefined.
[3:16] Let's refactor this a little bit and be a little more defensive in our code. What I'm going to do here is instead of currentCard, I'm actually going to destructure the card object that we're going to get back.
[3:28] I'm going to grab the term out of that, assuming the card exists. I'm going to give it a default value of an empty string. On the right-hand side of the equal sign, I'm going to check and just make sure cards is a truthy value, that it's not undefined or null.
[3:43] If it exists, I'm going to check that cards.length is truthy, meaning it's greater than zero. If that works out, then I'm going to return cards of currentIndex. We'll get that card back. Then we'll destructure it to grab the term, which has a default value of an empty string in case we don't get anything back.
[4:02] Then I'm going to come down here. I'm just going to get rid of that reference to currentCard. Now I'm just referencing term, which is defined here. It should fall back to an empty string if cards isn't defined or if it hasn't been populated yet.
[4:14] When the API call comes back and we have cards, we'll get a new render. This will get reassigned. Then our term should show up here. Let's save that. Switch back to the browser. When it reloads, we'll see that everything works. It doesn't break on that initial render.