4.7 Creating the Chirp List Component
Now that our users can create chirps, we want to be able display those chirps in a list. We'll create a component to do just that in this lesson.
1.Getting Started2 lessons, 03:51
2.Project Setup3 lessons, 20:58
3.Server-Side Code6 lessons, 53:00
4.The Client Side16 lessons, 2:43:53
5.Conclusion1 lesson, 00:29
4.7 Creating the Chirp List Component
In the previous lesson, we created our Chirp input box, which allowed our users to actually write a Chirp, and we managed all our actions so that that Chirp was actually sent to the server and received back in its saved form. So now we're ready to actually display those Chirps on the user's home page. So let's create our Chirp list class. I'm going to create a new file in src/components, and this is going to be ChirpList. And again, we're gonna start by requiring react. And then, let's create the Chirp list class. Now, you might think our first job in ChirpList is to actually get that array of chirps from the ChirpStore, right? Well, not exactly. Remember that we have this home class where the Chirp list will eventually live. We're actually going to get those Chirps in the home.js file, and then we'll pass them to the Chirp list as a property in the same way that we passed the saveChirp function down to the ChirpInput as a property. So in here, we don't have to do any getting of state. We can just start rendering. Now before we write this render function, why don't we actually get those Chirps in home so we can see how that's coming in. Let's require the Chirps store, so I can require the stores/chirps file, and then let's give this home class a getInitialState function. And remember, this function returns the initial state, so it'll return an object here and we can say chirps and we will say ChirpStore.all. Remember our Chirp Store has an all function and so this will just return all those Chirps. Now I wanna point out here that you may have noticed, when we get the Chirps from the server, we're getting all the Chirps, which means all the Chirps from all the users. Now of course, if this application was going to be as big as Twitter, that would just break everything. However, since we're building a small example application here, we're not going to worry too much about getting all those chirps. By the end of this lesson, the homepage will display all the Chirps in the entire system to the user on their homepage. Now, as we get further on and create the ability to follow and unfollow users, we'll make sure that the homepage only shows the Chirps of the user themselves and anyone they're following. But for right now, we're just gonna display all those Chirps and keep things a little bit simple. So once we have these Chirps, we actually want to create our chirp list element. Of course we'll have to require that first, so we'll say ChirpList equals require the ChirpList class, and then, underneath ChirpInput, let's include ChirpList and we'll give it a chirps property which will be this.state.chirps. Excellent, it's that simple. So now that we can see really where these Chirps are coming from, back here in ChirpList we know that we can get a list of these Chirps by doing this.props, which is the object that has all of the properties, .chirps. Now, this render function's main job actually is rendering a whole list of chirps. So when we render a list like this, it's easiest if we just map over it, and I'm going to store these in items. So we have a function here, of course, our callback, and it will loop over each Chirp individually. And we can actually return a jsx item here, so I can have a list item, right, that I want to return. Now when we have a bunch of sibling elements in react, react likes us to give these elements a key property. In this way, it can easily distinguish between them. And of course, this key needs to be unique. Now each of our chirps has a CID property which is, of course, its ID number. Those will be unique, so we can just pass that as the key to our list item here. Now within here, we can make this very simple, for starters. Why don't we show a strong tag, and inside this strong tag we'll say chirp.username, and then we can say chirp.username said, and then let's just put quotes here and in here we can have chirp.text. This will be really, really simple. We'll just have username said and then whatever they said in their chirp. All right so after this loop finishes, our items array here will be an array of these list items. So now all we have to do is return an unordered list here from our render function. And inside of it we'll just put our array of items. It's really that simple. The final thing to do here in chirps list is to export the module. So we'll say module.exports = ChirpList. Excellent. So that is all we need to do for now in our chirp list here. And since I have gulp watching, and server running, I can come back to the browser and just refresh the page. And it seems like we have an error because nothing new is showing up. But we don't have any errors in the console, which makes me wonder if there's an error in Gulp. So I'll come over to the terminal here, and as you can see, that is the case. The error that has been repeated a few time here, is that there's no module stores/chirps found from the home component. And this is just an issue of the incorrect path. So if we come back to home js, the problem is that the stores directory is actually one directory above the components directory so we have to do the two dots there instead of the three. If we look at gulp one more time, we can see that everything seems to be running fine. So let's come back to the browser and refresh the page. And still, we don't see anything new. Now, at first this might seem like a bug. But if you think about this for a minute, you might understand what's going on. We might understand a little better what's happening here if we come back to our main JS file. And, actually, I'm gonna clean this up just a little bit. First of all, we don't need ChirpStore in here any more because ChirpStore is actually being required through this home component, right? So we can delete ChirpStore here. But here's what's going on. So at this point in our code we're fetching all of our chirps from the server, right? So our store is going to have all those chirps. But then immediately after that we're running our roots. Now, this means that at this point in our code the homepage will be rendered. However it is the case that our routes will be rendered before API.fetch chirps has returned which means that when our home js class is running and getting all the chirps from the chirp store, there are no chirps in the chirp store yet. They haven't come to the browser yet. So, what we need to do is set up this class so that not only does it check for chirps when it initializes, but also it is listening to the chirp store to see if any new chirps are ever added. Of course, this makes sense not only in this case when we're initially loading the page, but later on when we're pulling the server for new chirps to be added to the chirp store, we want our homepage to update with those new chirps when they're added to the chirp store. Now of course, we anticipated this when we created our store. You might remember that here in store JS we have these addChangeListener and removeChangeListener functions, so this way we can actually be listening for changes from the home class. So, let's add another method to this home class. Underneath getInitialState we will add componentDidMount. Now, this is a specially named react function, and this function will run after this home component has successfully been mounted into the Dom. So what we want to do in here is start listening for change events on the ChirpStore. So we can say ChirpStore.addChangeListener and we want to pass change listener a function that will be run whenever the chirp store is updated. So we'll call that this.onChange. And underneath this we can write that on change function. Now, in here it's pretty simple we just want to do this.setState because whenever we set the state of our component it will rerender if appropriate. So we want to pass an object here to set state. And it just so happens that the object we want to pass to setState is exactly the same object that is returned from getInitialState. So what we can do here is actually call this.getInitialState. It's a little bit of a hack, but I think it's neat to be able to recall, get initial state, and get our fresh set of chirps. Now it's important that we also include a componentWillUnmount function here. Because here's the scenario. Our application will have multiple routes and right now we're creating the home route, however we will have, say, a profile page route. And so when the user navigates from the home route away to the profile page route, this home component will unmount. However after it's unmounted, it's possible that the ChirpStore will update and, since we have this event handler here, React will complain that we're trying to update a component that isn't currently mounted. So what we have to do is say ChirpStore.removeChangeListener and we want to pass at this.onChange. The very same function that we registered as a change listener in the component did mount function. So with these three new functions in place we should be able to see our chirps on the page. So I'll come back to the browser and refresh the page. And notice that we still don't see any thing new. Now we've just made sure that this home view is successfully listening for those change events and we can see from the terminal that we have got the chirps. So the problem here must be in our actual chirp store. Either these chirps are not being successfully received or when they are, the store is not emitting any changes. So let's open up the store's /Chips.js file and as you can see, right here we are binding to the got Chirps event and we're calling this store's set function. So if we go over to store.js everything looks to be in order here. So it seems that the store is successfully receiving the chirps. So the other problem is, is the store not emitting the change when it happens? Remember we have these addChangeListener and removeChangeListener functions which register listeners for the change event. However we also have this emitChange function which we need to call to actually emit the change event whenever a change happens. So we do that down in the function that we registered with our dispatcher right here you can see we are calling the function will actually update the store, this is where the problem is right underneath this we need to do store.emitChange. There we go. So if we update that file, now everything should work in our application. So if we come back to the browser one last time and refresh the page, there you go. Now, you can see our first chirp showing up here on the page. And in fact because our Chirp store is actually bound to the Chirped event, we should be able to make another Chirp. And when I press Chirp, you can see that it is both added to the server and it displays here on our page. Excellent. So that is our initial Chirp list. Right now though, our Chirps are looking a little bit sparse here, so why don't we pretty this up a little bit in the next lesson.