- Overview
- Transcript
4.4 Creating the Chirp Store
Now that we have a store class, we can create our first store: ChirpStore
. This is where our chirps data will be held in client machines.
1.Getting Started2 lessons, 03:51
1.1Introduction00:57
1.2Application Demo02:54
2.Project Setup3 lessons, 20:58
2.1Setting Up a Gulpfile10:02
2.2Creating an Index Page05:45
2.3Starting the Server05:11
3.Server-Side Code6 lessons, 53:00
3.1User Accounts Overview07:23
3.2Configuring Passport08:55
3.3Installing Middleware05:21
3.4Writing the Login Template06:14
3.5Writing Login Routes19:23
3.6Creating the Chirps API05:44
4.The Client Side16 lessons, 2:43:53
4.1An Overview of Flux06:00
4.2Creating Constants and Actions16:22
4.3Writing the Store Creator14:13
4.4Creating the Chirp Store12:59
4.5Writing the App Component07:16
4.6Creating the Chirp Input Component17:55
4.7Creating the Chirp List Component10:31
4.8Creating the Chirp Box12:46
4.9Creating the User Store07:52
4.10Creating the User List Component16:12
4.11Creating the Follow Button13:51
4.12Sorting Stores02:13
4.13Creating Navigation03:13
4.14Creating the User Profile11:59
4.15Writing Store Mixins07:47
4.16Doing Server Polling02:44
5.Conclusion1 lesson, 00:29
5.1Conclusion00:29
4.4 Creating the Chirp Store
Now that we've created our store constructor, we're ready to create our first actual store. So in that stores folder that we created, source/stores, I'm going to create a chirps store. So, I'm going to call this chirps.js. Now, the first thing we're going to do in this chirps store file, is we need to pull in the constants file. So I'm going to say var constants = require, and that is one folder up, so we'll say ../constants. And we need that because we'll need to reference some of our action names which are of course in the constants directory. So now we need to create our Chirp store. And since this is the only thing in this file, it's also the thing that we want to export. So I'll say ChirpStore = module.exports. And now we need to call that extend function that's in our store file. So, I'm going to require our store file here. And we can do this, as we've already done several times. We can just require inline. And there's nothing wrong with doing that. So, we'll require the store file and then we will call the extend function. And now, anything that should be specifically for the ChirpStore should go inside this object. Now currently, there's only one thing that we need and that is we want to override the default initialization function. So, let's create our own init function. And of course, remember, as we planned in a previous lesson, the init function is where we say that we want this store to listen for specific actions in our system. So, we can do that through the this.bind function, remember. And the first parameter to bind is the name of the action that we want to be listening for. So we can say constants.gotchirps for example. Now this is something we want our Chirps store to do. Whenever new chirps enter the system coming from our web server on the back end, the GOT_CHIRPS action will occur. And this store needs to listen for that and perform an action when that happens. What action is that? Well, it's this.set. As you know, the set function here is one of the methods we gave our stores, and so whenever we get an array of chirps from the server let's add that to this store. The other thing we want to do is whenever a user creates a chirp it will go to the server to be saved. And when it comes back we will have constants.CHIRPED, that's the name of the action that will occur when that chirp comes back from the server. So that's just a single chirp. So when that comes back from the server, we're going to say this.add. All right, believe it or not, that is our whole Chirp store. For now, at least anyway. We may come back later on and add some custom methods to get specific chirps out of this Chirp store. However, for now, that's all we want. Now, we've been talking a lot about getting chirps from the server. However, we don't have any code yet that does that. So let's do that. You might recall from our flux overview lesson that we said we were going to need an API utility to interact with that API on the back end. So, in our source directory let's create an API file, api.js. And let's create an API object. And of course again we'll do module.exports for this API object. And in here we want to have a fetchChirps function. And we'll use this function to go to the server and get the chirps from our API. Now, you might expect me to use an XML HTTP request in here, and in the past that's what I would have done. However, more recently a lot of browsers are supporting the new fetch function, which allows us to get a route from the server. So for example /api/chirps, and it will actually return it as a promise. Now, we're going to be doing this a couple of times, so I'm actually gonna wrap this fetch call in a method and we're gonna call that get, of course, and we'll pass it the URL. And so in here we're actually gonna return our fetch call. And let's see, the first parameter to fetch is of course the URL, but then we need to pass it an options object and we need to give it the property credentials. And we need to set that property to same-origin. Basically, what this means is, we're telling the browser, when you make that request to the web API, make sure that the server knows that this request has the same origin as other requests that came from this browser. And the way it does that is by sending the cookie headers along with it. If I left out this credentials option, then what would happen is we would make the request to the API, however, the API would not know that we are a logged in user. Remember, if we go over here to the chirps.js file on the server, you can see that we are checking. Before we respond to an api/chirps request, we're checking to see that the user is logged in with our login.required function here. And so, if the user was not logged in, instead of returning the chirps, it would return the login page, and so the response to this fetch would be the login page. And of course, that's not what we want. So instead, we set the credentials to be same-origin. And that way the sever knows that we are an authenticated user. Now, as I mentioned, fetch here will return a promise. However, the data for that promise Is a response that has a JSON method. And unfortunately, that method doesn't return just the raw JSON. Instead, it returns another promise that will eventually return that JSON. So I'm going to add a .then call to the end of this promise so that we're not going to return the fetch promise. Instead, we'll return a second promise. This first promise here, of course, will take the response but then we want it to return response.json. So the actual promise returned from the get function will be res.json and so this we can expect the JSON directly from our get function. So, what we can do inside fetchChirps is we can say get('/api/chirps') and we can say then and this function will directly receive our JSON. And what do we want to do when we get that data from the server. Well, remember, as we've been looking at our stores, when that data returns we want to have a GOT_CHIRPS action. So we need to get our actions file and call that GOT_CHIRPS action. So, let's create a variable here for actions. And we're going to require the actions file, and then in here, we can say actions.gotChirps, and we'll pass that data directly through. And so we know, because we've created these actions, that behind the scenes, when we're calling actions.gotChirps, this data will be added to an action object. Which will go through the dispatcher and come out the other side into this Chirp store. Now, there's one more way we can actually make this a little bit cleaner. Because we're passing JSON as a single parameter to actions, and that's the same single parameter that our callback here gets, we can actually remove this callback function and just do actions.gotChirps. And we can bind it to the actions object just to make sure that that will work correctly. So there we go. actions.gotChirps.bind to the actions object and that makes our fetchChirps function here nice and clean. All right, we should be able to actually see this fetchChirps in action here. Let's open up our src/main.js file. And let's see, let's clear everything we've got here. And instead, let's just get that API, and then we can do API.fetchChirps. And if you think about it, you should be able to figure out what this should trigger. First, it will trigger a request to go to our API. When those chirps are returned we'll send out the GOT_CHIRPS action and we should see two things in response to that. First, we know that our dispatcher file is registered to receive any actions and it should log that action to the console. Second, we know that our ChirpStore is listening for the GOT_CHIRPS action, and it should set any chirps that it receives as the data for that ChirpStore. So let's go over here to store.js, and just at the very end of set here, let's just say console,log, Data set. Underneath thatm why don't we just console.log this._data. Now currently there are no chirps on the server, so we'll just get an empty array back. However, it should still go throughout the motions of sending that action throughout the system even though that's an empty array. Now, before we look at that in the browser, I'm looking at this here in the terminal and you can see that this is the output from the gulp watch task. It's been running behind the scenes as we've been making these changes to the files. And so, we will have the latest version of our files compiled and ready for us to use in the browser. Of course you'll need to make sure that the server is running. And now I'll head to localhost, port 3000. And of course I'll have to log in. And now if I pop open our JavaScript console, you can see that we have, well we only have one thing put out to the console, and that is the action that is actually just being logged from the dispatcher. As you can see over on the right-hand side here, you can see this comes from dispatcher.js on line six. So what we have here is an object, it has an action type, GOT_CHIRPS, and the data is just an empty array. You can see, it says array with zero items. So that's excellent, our dispatcher is actually handling our action. However, why don't we see any output from our store? Well the reason for this is pretty simple, actually. The store is currently not part of our bundled application. The reason for this is that our bundling starts here in the main.js file, and the main.js file only requires the api file, and the api file requires the actions file, and the actions file requires the constants file and the dispatcher file. However, none of the files, yet, that come off this main.js file require our ChirpsStore. So, that was never actually bundled with gulp and browserify, and therefore can't actually be run We can easily solve this problem if we just require the ChirpStore, here, in our main.js file. Eventually, we will have other files which are referenced from this main.js file, which in themselves will require the ChirpStore. However, for now, this will work. If we come back to the browser and refresh the page, you can see we're still not seeing anything. So let's double-check our gulp task to make sure everything's working. And as you can see, everything is not working in the gulp task. We have an error. The module event is not found in the store.js file. So, we're going to have to go fix that but before we do that, I just wanna point out that this is why we installed the gulp plumber task. As you can see our gulp task continued to run even though there was a problem in completing the task. Now, in this case, it's a simple typo. That should probably be the events module, not the event module. However, in many cases, I find I'm saving my files often as I go through them. And so, sometimes, I save them when maybe I haven't yet written the closing curly brace of a function or an object or something. And that would cause an error in this watch file. However, because I'm gonna continue writing that in just a second and save again, having plumber in place means that gulp will just wait for me to continue writing and then it will try to compile again after I've resaved a file. So if we come back to store.js, you can see right at the top here where we create the EventEmitterProto object, we required event, but that should be required events. So I'll save that and if we come back to the terminal, you can see right at the bottom here that the task ran again and we don't have an error showing at the bottom. So that means everything compiled properly, so if we come back to the browser we should be able to refresh the page. And you can see that we have some more output here, but unfortunately it's an error. This says that we cannot read the property map of undefined. Okay, let's go look at that line. As you can see that's where we're getting the current IDs of the data that we currently have. So we're saying we can't use map of undefined, so that would mean that for some reason _data does not exist on our store. Which is of course the value of this. So let's just make sure that we have that data property, so I'll console.log this. If we come back to the browser and refresh the window, you can see the value of this is actually the window. Okay, that's wrong. So the reason this is happening Is because when we call set, it doesn't have this store object as its context. Well set is being called from this line right here, right? We pass set as the second function here, this should be bound to the store object. However, in our bind function, what are we doing? It's not in bind, it's down here in require. When we call this function inside our register block here, we pass null because I said at the time that the scope didn't matter. However, that's not true. We need to pass the store as the object, that should be the value of this. Okay, with that in place, we can come back to the browser, refresh it one last time, and there you go. We can see that we have our data set message, and we have an empty array. And of course, these values are coming from the bottom of our set function here. So I can delete those from our set function, and you can see that things are starting to take shape. Even though we don't have any UI yet, we have a system that can take data and will move it around to the right place. So I think that means we're pretty much ready to start creating a little bit of user interface, and so we'll look at that in the next lesson.