
Microblog 1
  • Overview
  • Transcript

4.6 Creating the Chirp Input Component

In this lesson, we want to create the input area where a user can actually write a new chirp. So lets start with the component. We're going to create a chirp input component. So I will create a file in the source components folder, and I'm going to call it ChirpInput. We'll start of course by requiring react and then let's create our class. So I'm going to call this chirp input, and we'll do React.createClass. All right. Now, the first thing we want to do here is get some initial state. This of course, is a function, and it returns an object. And in this object are whatever properties we want to be initialized when we create this class. In the case of this component, all we're interested in is the value that our user rights in the chirp input box. So when they start of course, this value is an empty string. So we'll set value equal to an empty string. Next, we'll write our render function, where we return our HTML. So, we'll start with the div, and this div will have a class name of row. Because we want our chirp box to take up an entire row. Now in here we want to have two columns within this row. And the first one is going to be nine columns wide, and this is going to be our actual input element. So inside of this, we will have our input tag. And this is going to have a couple of attributes. First, let's give it a class name of its own. Just like we did on some of the input elements in the log in and sign up forms, we're going to add the utility class full-width, so that this input element will take up the full width of the element that it's in which is our nine column div. Next we'll set its type equal to text, and we can also give it a place holder value which will just be Say Something. Finally, we just want to listen for the change event. So, we can say on change which will occur every time the user changes the contents of this input element. Basically, this means whenever they add or remove characters from the input. When this happens, we want to call the this.handleChange function. All right, and that will be the end of our input element. Now we're going to have to write this handle change function so underneath render here, let's add our handle change method. And of course since this is a DOM event, we will get an event object as a method to handle change here, and it's very simple, all we want to do is say this.setState, and we will set the value state equal to the evt.target.value. So whatever the value that the user currently has in this input element will be saved in our state object in this class instance. So this way, at any moment in time, the value that we have stored in state matches whatever the user has in the input box. Now when the user is done writing their chirp, they're going to click the chirp button. So we need to give them that button, and that will be a div that is a sibling to our nine columns. This one of course is going to be three columns. This is going to be a button element. This button element will have a couple of classes here. First of all, we're going to give it the same class as the input, so we'll say u-full-width, so that it takes up the full width of the three column div that it's inside of. Then, we're also going to give it the button-primary class, which will give us a nice blue button. I think that's what we used on our login page as well. Also, we need an event handler on the button, and this is an onClick handler. And this will be handle click. And that is the end of our button opening tag. Inside this, we'll just include the text chirp, and then we can have our closing button tag. So the bottom of our class here, let's add the handle click function, and in here we have to decide what to do when the user clicks that button. Now we know what we want this button to do. When the user clicks that button, the text that they typed into the input box should be turned into a chirp object and sent back to the server to be saved, and then the server will respond, saying that it's been saved. Of course at this point, our chirp store will grab that action and include the newly saved chirp into the chirp store, and then at that point, we'll have a list of chirps which will be updated with the new chirp from this user. However, how do we begin that string of events from inside our chirp input box. Well we actually don't worry about it too much, because here's what's gong to happen. Down below here, let me upon up a little comment and show you how we expect chirp input to be used. What will happen is we will have our chirp input element created like this somewhere else, and we want to decide what the chirp input should do at that location. So we'll expect our chirp input element here to receive a property on save. And on save will of course be a function that will be called, but it will be called in the context of wherever we include this ChripInput element. So within ChirpInput, we don't have to worry about exactly what onSave does, we just know we need to call onSave. So here's what we can do. Inside handleClick, we'll say this.props, which is the object by which we have access to any properties that were given to our element when it was created. We can say this.props.onSave, and let's pass it this.state.value, so whatever value is currently in our state at the time of the button click. And of course, because of our change event handler here, it will be kept up to date with whatever is in the input. All right, so that's almost all we need to do. However, if you think about it, there's one bit of clean up that we need to handle. At this point, the chirp will have been saved, and probably show up in the user stream, however, that chirp's value will be in the input text box, so we need to remove that content. Now, there are a couple of ways we could handle this. But I think the easiest way to do it would be to bind the value of the value property to the input text box here. So what we can do is say set the value of this text box to be equal to this.state.value. Now you might wonder if this will cause a problem, because when we update the input text value, then our change handler here will update the state value property, which will in turn update the input, which will in turn update the state. Well, not exactly, because react behind the scenes will compare whatever value is currently in the input with the value that we're telling it to set. And if they're the same, it won't actually do the change. So this doesn't actually have any performance compromises. However, what this does mean is that inside handleClick here, we can say this.setState, and we can set the state of value to an empty string. And when this happens, the value property will be different than what is currently in the input text box, and it will update to the empty string. All right, so the last thing we have to do in this class is export it. So let's do module.exports = ChirpInput. Now this ChirpInput component is going to be part of our homepage. Right now we don't have a component that renders the homepage. So let's do that. Let's create another component in the src/components directory, and we're going to call this one Home.js. And of course, we'll start by requiring react, and then we'll create a class and we'll call it home. And again, we'll do react.createClass. Now this home class is going to display two things. One of them is the chirp input component that we just created, and the other one is the chirp list component, which we're going to create soon. Of course, the chirp list component is a list of all the chirps that this user wants to see. However, we'll get to that list later. For now, let's go ahead and write a very simple render function. All we're going to do here is have a div element, and inside this div, we'll eventually have both the chirp lists and the chirp input, but for now let's just do chirp input. Now remember as we just saw, we're going to want to add an onsave property here, so I'll put that in and finally of course, we can't just refer to chirp input this way, we have to get it. So let's get the chirp input class. And this is in the same directory as home, and it's called ChirpInput. Now as our onSave action to the ChirpInput element, let's pass this.saveChirp. And, of course we'll have to create that method. So underneath render, let's create the saveChirp function. And we know that this function will take the Chirp text, the text that was in that input box. And what we want to do here is call one of our actions. You might recall, that one of our actions is chirp, and this is exactly the case where we want that action to take place. So we want to fire a chirp action with the chirp text here as its data, or its payload. So to do this, we're going to need to require our actions object. And we can require this, and this is one directory level up from the components, so we can say ../actions. And then here inside of saveChirp, we can do actions.chirp. And let's pass the text in as the payload. All right, so at this point that's really all we need for our home view here. Let's go ahead and actually render this home view when we're on the home page of our application. So let's go ahead and open up our main.js file, and let's add another route. Now in the previous lesson, when we were talking about routes, I said that the route that we've created here is for our homepage because it doesn't have a path. That's only partly true. The truth is this route will actually be used for all of our routes, because we're going to nest some routes within it. And so even when the user goes to these nested routes, the wrapping route will still be rendered. So our app here will be rendered. But then as we saw in app we want to have some nested content. So let's create our first route within the app route. So again, we're going to use the react router route class, and since this route will not have any nested routes, we can just do the self closing thing. And let's give this route a name, which will be home. Now since the name of the path are not the same, we have to give it a path as well. In our case, that path will be just /the root. And now we want to give it a handler. And the handler again, we'll do our require statements in here, and we'll say require components/Home. So now what's going to happen is when the user browses to our slash route or our root route, ReactRouter.run down here is going to again, render this root react view. However, this time, the root class will be a combination of our home class and our app class. Now right now our app class doesn't actually accept nested content, so we have to make a little change there. Let's open up source/components/app.js, and we want to get the react routors route handler class. So I'll add a variable here for the route handler class, and I can just require react-router.RouteHandler. Then, down here where I have nested content coming, I'll replace that with the RouteHandler element, and we can just make that self-closing, and now tist RouteHandler class here will be replaced with whatever nested route we have. So in the case of our home route here, it's going to be the home element. Now I still have our server and the gulp watch task running, so I can just come back to the browser here and refresh the page straight away, and it looks like we may have an error, because nothing's coming up here. If I open up the JavaScript console, we can see that the first warning we have here is invalid prop handler of type object supplied to route, but it expected a function. Okay, so there is something wrong with our handler property, so lets go back to main js here and check that out. We know this isn't our app component, because that already worked, so there must be something wrong with our home component here. If you look back at home js here, you can see that we forgot to export the module. So lets do module.export = home, gulp watch is watching, and so it will immediately rerender this, and now if we come back and refresh the page, oh look at that, excellent. We have our chirp box and our chirp button showing up. Let's go ahead and write our first chirp, so I'll just say our first chirp, and now if I click chirp, notice what happens. First of all, the UI works fine because our box is emptied. Second of all, look down here in our console. Because we have our dispatcher logging all of our actions, we can see that the chirp action is taking place here. Notice the object that was logged. We have an action type of chirp and the data, our first chirp. So this means that our application is starting to work according to the flux architecture. We're almost there. We just need the api utilities that we've started to create to grab this action and start working with it. So lets go ahead and open up our source/api.js file. And what we want to do is at the bottom of this file, we need to register a call back with the dispatcher. So, that would mean first at the top of this file, I should request the dispatcher, so we'll say dispatcher = require the dispatcher file. Then, down at the bottom here, we can say dispatcher.register, and we'll pass at a function, and of course this function takes our action as a parameter. All right, and in here we have to do something different depending on the type of action. So we'll use a switch statement, which will make it easy to compare multiple types of actions. We'll switch on action.actionType, and we're going to need to compare that action type to the constants. So let me also require our constants file here. So at the top, I'll require constants, and now, inside our switch statement, we'll have a case of constants.CHIRP. Remember, that's all uppercase. And whenever that happens, let's call API.saveChirp. And we will pass it the action.data, which we know is the text of our chirp. And then we'll just break after that. Now, later on we'll be adding more cases to this switch statement, but for now that's all we need to worry about. Okay, so up here in our API, let's add the safe chirp method. So we have fetch chirps, so underneath that we'll create save chirp, and of course this function takes the text of the chirp as its parameter, because that's what the data of our action will be, and let's start by doing a little bit of cleanup. We'll set the text equal to text.trim, and then we will say, if text = an empty string, we'll just go ahead and return. Otherwise we want to go ahead and send this to the server. Now you might recall from our trips API. Let me open up this file. We have this post function right here. We want to post to the /api/chirps route. So this is what we need to do. We need to make a post request. Now right now we have a helper function for get. Why don't we go ahead and create a similar one for post. So underneath our get function here, let's create a post function, which will take a url. And once again, we'll have the same promise scenario that we have above. So we'll return fetch, we'll pass fetch our url, and then we need some options here. The most obvious one first, of course, will be the method, which should be post. Then, again, we'll need to include our credentials, so that the server will realize that this user is logged in. However, when we're doing post requests, instead of using the same origin value for credentials, we have to use include. So that will include the credentials with this post request. Of course, the other big obvious one is the body of the request. So let's take the body as a second parameter to our post function here. And this body of course needs to be a string, but we'll expect them to pass in an object, so let's do body = JSON.stringify, we'll convert this object to a string and we'll do the body. However let's also pass an empty object as the second parameter just in case they don't include the body when they're calling POST. Finally, let's add a couple of headers here. We'll say that the content type is application.json. So the server knows what's coming in, and we'll also see that we accept application/json as a response. Excellent. So that should be all we need to do for our fetch here. Now we expect the response to this to be some json. However, remember a fetch will make this a json promise, so lets have a then statement after our fetch call here, and we will just return res.json from that promise. So, our post function here will now return a promise of the actual response body. Now we can use this very easily up here in saveChirp. We can do post and we're posting to /api/chirps. We want to post an object where the text is equal to the text that was passed in. And then we can say, then after that occurs, we want to call another action which let's everybody in the application know that this chirp has been saved. Now, you might remember that this is the chirped past-tense action, and so we're going to call actions.chirped, and let's just bind this to the actions object. And this way, actions.chirped will receive as a parameter the response from this post request, which will be our saved chirp. Okay, so we should be able to see this all in action. If I come back to the browser, I'll refresh the page and let's see what happens. I'll make another chirp here called our second chirp. Let's go ahead and click the chirp button. First we can see we have our chirp action, right? Where the data is our second chirp, and that's great. But then there's another one underneath it, and this is the action chirped, which we know occurs when the response gets back from the server. If we open up this object and look at the details of our data here, you can see that all of the details about this chirp are in place. We have dates for created and updated. It has its own ID, but it also has a reference to the user's ID. You might think that zero is actually an error, however the database that we're using actually starts its ID counting at zero, so that's fine. And we have the text of our chirp right there, our second chirp, and we also have some other information about the user. So that's excellent. We are now creating chirps. That's perfect. If we refresh the page at this point, notice now that the action that we're calling from the main file, got chirps, is actually returning an array with a single item in it now. Because our system now has a single chirp in it. So, this means we have some data the we want to display on this homepage here. So now in our next lesson, we're going to build our chirp list view.

Back to the top