- Read Tutorial
- Watch Guide Video
So let's walk through the behavior we're looking for. So on the page right here, I have one of our sample blog posts up, and what I'd like to be able to do is to simply click on the title here and then have the entire page transition to use the blog form. Now I do not want to move to the edit form, so I don't want to create a new page or anything like that.
I simply want the content to be wrapped up inside of our blog form, and this is a click to edit feature. It's something that you most likely will have to learn how to build and to add to your own applications in the future. So let's start building out part of this in this guide.
I'm gonna open up Visual Studio Code, and inside of our blog detail component here, I'm first going to add a new piece of state. I'm going to add what I will call the editMode, and I'm gonna set this to false by default. So this is gonna be our piece of state so that we can monitor and the component can monitor if we're in edit mode or if we're just in the regular view mode. If we're in edit mode, then the form should be what shows up. If we're not in edit mode, if editMode is false, then we should see the content, just like the regular blog detail page.
So now that we have this, we're gonna need a function. We're gonna need a handler that is going to take care of the process, so let's go and bind that to this. So I'm gonna say this. and let's just call it handleEditClick and bind it to this.handleEditClick, bind to this, and let's just copy this method name and create it.
It's not gonna take any argument, and inside of handleEditClick, we first will just console log this. So let's just make sure this is all working, so I'll say handle edit clicked and that's all we need to do there.
blog-detail.js
handleEditClick() {
console.log("handle edit clicked");
}
And now let's just go and add this to our title. Now you could wrap the entire div in this click handler, but I'm not gonna do that myself because there's many times where I go and I reference my own blog posts, and I will copy and paste something. And what this is going to do is if I were to do that, it would transition into the edit mode, which isn't the behavior I want as the blog owner.
But it is completely up to you. You can add this click handler anywhere you want, for me, I'm just going to add it to the title. So for the title here, I'm going to add onClick and then set this equal to this.handleEditClick, just like that, and hit save.
blog-detail.js
return ( <div className="blog-container"> <div className="content-container"> <h1 onClick={this.handleEditClick}>{title}</h1> <BlogFeaturedImage img={featured_image_url} /> <div className="content">{ReactHtmlParser(content)}</div> </div> </div> );
Now let's open up the JavaScript Console and now if you click on Content page, you'll see that it is working and it's saying handle edit clicked, so our click handler has now been installed and we can use it.
Now the next thing we need to do is to have that update our state, so handleEditClick should say this.setState and should update editMode and set it equal to true. So this is not gonna do anything right now, obviously, because we have not made our render do anything and we haven't had it change its behavior based on the edit mode, so that's what we need to do now.
I'm not going to include this logic in the return statement and the reason for that is because what we're going to implement is going to be slightly longer than code that I'd like to place in a single conditional.
So instead, I'm gonna create a variable up above the return statement and I'm gonna call it const, and then let's just call it contentManager, and this is going to be a arrow function. It's not gonna take any arguments, and now this is gonna handle the logic for our content. So I'll say if this.state.editMode is true, then I want to return the blog form, so I'm gonna say return BlogForm.
const contentManager =() => { if (this.state.editMode) { return <BlogForm/> } }
Now let's make sure to import our blog form at the very top of the file. So let's say import BlogForm from ../ and then we want to go to blog and then blog-form, so now that we've imported that, we can actually use it.
import BlogForm from "../blog/blog-form";
Then the else condition, so in other words, if editMode is false, then I want to return all of our normal content. So to do that, I'm just gonna come down here and grab each one of those elements, h1 tag, our blog featured image, and then the div, and I'm gonna grab that and I'm going to put it up here. And you know what, actually, I think I'm gonna grab this entire div, and I have to because we have to have a div wrapper, a single element, and so I'm gonna place that inside of here and make sure that you actually are returning that. So return with the parens and then close out the parentheses, and that's all we need to do here.
blog-details.js
const contentManager = () => { if (this.state.editMode) { return <BlogForm />; } else { return ( <div className="content-container"> <h1 onClick={this.handleEditClick}>{title}</h1> <BlogFeaturedImage img={featured_image_url} /> <div className="content">{ReactHtmlParser(content)}</div> </div> ); } };
Now let's make sure to actually call this, so inside a blog container. Now we can call our contentManager and then close off that div, hit save here, And let me see, I believe that this should work. So let's go and test this out, let's see if we're missing anything.
return <div className="blog-container">{contentManager}</div>;
Oh, and it looks like we are, let's check it out and see what our error is. Oh, functions are not valid as React child, okay.
So if you ever see this, it means that you've called a function but you haven't actually had it run. So we're not passing this as a prop or anything like that. If you place a function inside of the JSX code and you want it to render, you actually have to call it. So add the parens to the end of contentManager, hit save, and then come back and hit Refresh, and it looks like this is working.
return <div className="blog-container">{contentManager()}</div>;
So I'm gonna click on Content page, and look at that, our form is now rendering and we are now in edit mode.
Now don't add any content or anything 'cause we haven't changed the blog form, we're gonna have to make some updates there. We're gonna pass in an edit mode, we're gonna pass in the blog that needs to be edited before we do anything so that it can change, 'cause right now, if I hit save here, it's gonna try and go and create a new blog post, which is not the behavior we're wanting. We want this to update or to change a preexisting item, so that is something that we wanna do.
If you hit Refresh right now, it's going to take us back to the Content page. Now if you notice, up in the top in the URL here, when I click on Content page, nothing changes because we've not left this route, and this is one of the most important elements I want you to understand in this section is that we're not working with routing here at all, and in fact, in every single element and feature we've built into this application, we haven't really been working with traditional routing because React and JavaScript, they don't really change the routes. The more mock the routes because we're working with a single-page application.
We only have a index.html file. We have one single file. We're simply swapping content in and out and we make it look like the routes are changing, so we're on the same exact page. The only difference is instead of all of the content being slid in, now we're saying that hey if we're in edit mode, I want you to just use the blog form, and I just want you to render that.
And this really speaks to the reactive nature of how React JS works, and I can tell you from experience, if you were to try to build this type of functionality that we just spent a few minutes on, if you were to try to do that in Python's Django or in Ruby on Rails or anything like that, this behavior would take quite a bit of work to implement, so what we're doing here is pretty cool and hopefully you're enjoying it.
So now that we have all of this, in the next guide, we're going to take it a step further where we're gonna start passing props directly into our blog form so the blog form will know if it is working with a new blog post or if it needs to edit one.