How to Refactor a React App into Components

With our Greeting App built, we're going to learn how to 'think in React' by breaking down our small App into components and refactoring it to use them.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Beginner's Guide to Real World React course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Beginner's Guide to Real World React, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Beginner's Guide to Real World React
  • [00:00 - 00:08] So, we've built our first app and it's looking and working great. Currently, it's using the class-based component approach, but we're going to refactor it to achieve a few things.

    [00:09 - 00:20] Get used to thinking about our apps in a component modular fashion. Try our hand at breaking down a larger component into smaller ones, and introduce the arguably more common functional component approach to building our React components.

    [00:21 - 00:32] So at the moment, we've got this large class-based component with all of the different things going on, including our event handlers here, for on change, and on click. And we've got a dynamic greeting and a title in there.

    [00:33 - 00:54] It's not a very large component, but you can see how easily it could get out of hand if we add more and more features and functionality to it. It's not very modular, and it's certainly not very reusable. It's good practice to analyze your components and try and break them down into smaller ones where possible and where it makes sense. This way, you can encapsulate functionality into smaller working parts, which can be duplicated and used in different places throughout your app.

    [00:55 - 01:09] So it's useful to have a look at larger component as a whole, and then think about smaller independent parts of functionality that it contains. These smaller moving parts can be broken down into components and used elsewhere. They'll no longer need to be tied into the single larger containing component.

    [01:10 - 01:22] To do that with our app component, we can look at what it's currently doing and see that there are three distinct functions that it performs that would be good candidates to be turned into separate components. So number one, it displays this welcome message in a heading level one tag.

    [01:23 - 01:37] This could have different styling applied to it in different parts of the app, or it could accept different messages on different pages, so it's a good fit to be separated out. Number two, it displays a dynamic message to the user here, including data from our state.

    [01:38 - 01:51] This greeting is quite simple and generic, and you might see it on the home page, but you might see it on a count page on main navigation, say in an e-commerce site to greet whomever's logged in. Number three, it accepts an input from the user here and triggers an event on a click of a button.

    [01:52 - 02:05] We're using the input and button combination here to accept a name, but it might also work on a contact form or as part of a search form, things like that. Being able to have these two connected elements in one place in a separate component makes it a great candidate for refactoring now.

    [02:06 - 02:19] So let's have a little look at a diagram of how we can group these three separate areas of functionality into independent components, a title, greeting and input. These child components can be imported into their parent, the app component.

    [02:20 - 02:26] So let's plan out the refactor. We have an idea of the components we need to build, and now we just need a set of steps to carry out our refactoring work.

    [02:27 - 02:31] So those steps might look like this. We'll create a components folder to hold our new components.

    [02:32 - 02:45] We'll create three new components, a title, a greeting and an input. We'll refactor the app component to use our new child component, and we'll ref actor the app component a little bit more from a class-based one into a functional component.

    [02:46 - 02:52] So let's do some refactoring setup. Now we have a plan. We'll need to do a quick setup before we start.

    [02:53 - 03:03] Like we did in the last lesson, we'll create all of the files that we need first, and fill them in as we go along, building out the components and refactoring them as we go. So first, let's add a new folder, and we'll call it components.

    [03:04 - 03:20] Within our components folder, we'll create three empty component files with the .jsx file extension, remembering to capitalize the first character in the file name. So we'll create a title, and a greeting, and an input.

    [03:21 - 03:43] So another thing to note here is that files with the .jsx extension are specific to the React library, and will typically contain familiar XML HTML-like syntax that we've been using in the earlier chapters. However, it's important to note that this file extension is down to personal preference.

    [03:44 - 03:58] .jsx files can be converted into raw JavaScript by tools, such as Babel.js, before being run in the browser. Some people prefer to have presentational components, which are ones that just accept static data and display it, using the .jsx file extension to denote them as such.

    [03:59 - 04:07] The important thing to remember here is that you can use either .js or .jsx to name your files. There's really very little difference. It just comes down to personal preference.

    [04:08 - 04:19] With that taken care of, let's start moving through the files and building them out, starting with our title component. So with startout by repeating our mantra, React must be in scope in order to use it.

    [04:20 - 04:36] The first thing we'll do, we'll import React before we do anything else. Instead of using a class-based approach previously, like we used for our app component, our title component would be our very first functional one.

    [04:37 - 04:43] So we'll define the functional component just as that, a function. However, rather than define a function, then set it as the default export afterwards.

    [04:44 - 04:54] We can do so in one line like this. We'll say export default, and then we can create our function props and return a h1.

    [04:55 - 05:06] Welcome to the app, just like we've got in our app component. Note that this is a nice style to have for smaller, less complex components, especially if they're purely presentational, like here.

    [05:07 - 05:18] However, if your components start to grow or feature very complex functionality , then might cause bugs. It makes sense to define your function and assign it into a variable, i.e. like a const. And then export it immediately afterwards.

    [05:19 - 05:37] This is because React debuging tools struggle to identify components that are defined and exported in a single line as we're doing here. So you can see we've got the default export which is a function that accepts a prop object, not props object, and uses an implicit return, that is without the return keyword and some JSX parentheses.

    [05:38 - 05:49] Because we're not doing any other logic, manipulating state, etc. We're just returning some JSX, we can use this implicit return here to make things look a little neater and remove unnecessary lines of code.

    [05:50 - 05:55] And that's it, sort of. We've got a heading level one being returned and we've got a fixed string in there, welcome to the app.

    [05:56 - 06:05] That's fine for our greeting app, but not very reusable if we wanted to have this component on another page that said something different. So we can make this title dynamic instead of it being hard-coded to a string.

    [06:06 - 06:18] And we can use our curly brace syntax again and use a value that we can pass in via the props object. So we'll replace this with props.title like this, which is great.

    [06:19 - 06:29] But we can take this a step further because we know we're only going to be passing in a title value via props. We can reference this value directly using object destructoring like this.

    [06:30 - 06:46] We know that props will expect and be passed a property called title. So by replacing props with some curly braces, we can now start to directly name properties that we expect props to have.

    [06:47 - 06:58] This in essence is JavaScript destructuring syntax and it's really quite neat. So as well as replacing the props argument in our function, we also need to replace the curly braces props.title here with just title as well.

    [06:59 - 07:06] What we're left with now that we're done is a really simple, small reusable component. It can be used wherever we need across our app in different areas.

    [07:07 - 07:15] It's also useful if you want to make changes to the way a title looks, which is styling or size or color tag attributes, things like this. All those changes can be made in this one single place.

    [07:16 - 07:26] The thing to remember is what we're making here is a very contrived example just to get a feel for React. But it's good to start thinking in terms of how you can use this in real world applications as you start learning and growing and building things for yourself .

    [07:27 - 07:34] This is something we're going to do further on in the car so that our apps start to grow and get bigger. But for now our title component is ready to go. So let's give it a save.

    [07:35 - 07:41] Moving on to the greeting component. So what we're going to tackle now is the greeting from our app components.

    [07:42 - 07:50] So this line here. You can see we've got a paragraph tag and a string and display name property that we're getting from state.

    [07:51 - 07:56] We can pull this out into our greeting component. So the first thing to do is start by imparting React.

    [07:57 - 08:12] So I'll impart React from React. And again, just like our title component, we're going to do an inline default export next along with an implicit return because all we're doing is returning one line, which is going to be our greeting with a dynamic name value.

    [08:13 - 08:35] So we'll do that like this. Export default. Notice that we can also repeat the destructoring syntax here to pull the name value from props.

    [08:36 - 08:54] The difference this time is we're going to add a default value for the name just in case it's not set. So we can happily do the same as we had in our app. We can do name or and then put our message in there using the logical or operator.

    [08:55 - 09:01] But I find doing it up here is a little bit neater. So I'll leave you to choose which way you'd like to do it as both produce the same result.

    [09:02 - 09:10] But this is going to be our greeting component complete. So the penultimate thing to do is to build out our input and button component.

    [09:11 - 09:16] This one's going to be slightly larger but still not very complex. We're going to impart React at the start of the component.

    [09:17 - 09:35] But this time we're going to add a little extra named import, use state. Because our input element replies on the app component state to keep track of its value, we need to use state in our new input component.

    [09:36 - 09:46] The problem is the input component is a stateless functional component, not a class based one. In order for us to use some form of state in a functional component, we need to use a feature of React called hooks.

    [09:47 - 09:59] In our case, to access state from a functional component, we use the use state hooks. Now hooks are introduced as part of React version 16.8 and they allow access to state and other React features without writing a class.

    [10:00 - 10:12] Don't worry about it for now, we're going to be covering hooks in greater detail in the next module, including use state. But for now, let's focus on getting the components built as you follow along and being familiar with the use state syntax for accessing state in a functional component.

    [10:13 - 10:34] So now we've imported React, we'll define our input component and export it right afterwards, making sure you copy in the input and button elements for our app component. So we'll define our component as input and then we'll pass it props.

    [10:35 - 10:56] And then immediately afterwards we'll do export, default and then export our input component. Notice how we've capitalized our constant variable here, input.

    [10:57 - 11:05] This is a convention, not a rule, but since we're creating a component, it's best practice to capitalize components names. So now we've got to update the input element.

    [11:06 - 11:17] Now remember from the first lesson we can't just have an input and a button side by side like this within the return statement. So to avoid that, notice how I've wrapped it in that familiar React fragment that we talked about in the first lesson.

    [11:18 - 11:30] The previous two components, greeting and title, both used an implicit return because they didn't have any logic to deal with, they just returned at their JS X elements. Our input component, however, needs a little more, mainly around setting values using the use state hook.

    [11:31 - 11:39] Because of this you can see that we've explicitly defined the return statement here. The contains our desired JSX output, i.e. the input and button elements.

    [11:40 - 11:56] Notice the difference from the app component which has to define a render method and then a return statement. You'll also see because the input component is a function, we don't need to define a constructor, nor call a parent class using the super method.

    [11:57 - 12:15] So what we've got here is a good looking so far but we need to make a couple of tweaks in order for it to work. So looking at the input element in our return statement, we're still referencing a state value here and a handle change event, both from our app component.

    [12:16 - 12:26] Neither of these two things work because of the differences between our app component which is class based and our input component which is functional. Luckily for us we can replace both things using the use state hook.

    [12:27 - 12:49] First let's define the hook at the top of our component outside of the return method and then start using it in the input method. So we'll type a const, type an array bracket, and then we call the use state hook and pass it in an empty string like this.

    [12:50 - 13:01] So it looks a little strange if you're not used to seeing this sort of syntax but the use state hook works like this. Number one, use state is a method that React provides as part of its core library.

    [13:02 - 13:16] You call it passing in whatever default value you want the particular item instead to represent. So for example we're using it here, we're defining use state and then we're calling it with an empty string which will set the value instead to that empty string.

    [13:17 - 13:27] The method returns an array with two items. So the first item represents the value held instead and the second item is a method that can be used to update the first item instead.

    [13:28 - 13:39] You can use the array destructoring syntax here in JavaScript to access both of these items. So in our component you can see that we're defining a const which is a destruct ed array.

    [13:40 - 13:51] This array contains two items. The first is going to be the value held instead so a name and we call it name but remember this is the title that we're going to be giving it. You can call it anything but we call it name as it's meaningful to us right now .

    [13:52 - 14:04] The second item will be the method that use state provides us to update the first value, the value held instead. So again you can call this whatever you like but the sensible convention is to call it the same as the name of the state value prefects with the word set.

    [14:05 - 14:14] So for us this means we'll call it set name. Now wherever we want to update the value of name instead we simply call the set name method passing in a new value.

    [14:15 - 14:36] Looking back at our input method down here we're ready to update its attributes to use this new state hook variables name and set name. So all we have to do is remove this dot state from the end of it from the start of it and we'll change this to EBT and we call set name.

    [14:37 - 14:48] With EBT dot target dot value. So the first edit is to change the location of our state data for the value attribute on the input element.

    [14:49 - 15:00] We can change where it was this dot state dot name to remove the reference to this dot state because that only applies to a class. The value is now going to be stored in this name variable here so we'll just refer to it as name.

    [15:01 - 15:10] The next thing to do is to replace the call to the missing this dot handle change in here on the on change event. Since we're going to be using the set name method that we got from our use state hook.

    [15:11 - 15:17] So we can actually simplify how we do this in line right here in the on change event. We don't need a separate function to be defined.

    [15:18 - 15:30] So using a simple inline arrow function here. We simply call the set name directly and we use the same EBT dot target dot value to reference the underlying value of the input element from the event.

    [15:31 - 15:38] The EBT argument that we passed in the on change event. Now notice that here is an important point.

    [15:39 - 15:52] You might be tempted to just call set name directly without an arrow function like this whole thing. However events like the on change event require that you pass them a function so that it can be called when the time comes by writing out the function directly.

    [15:53 - 16:08] So if we just had set name here and passing it arguments you're effectively invoking that function right away. Now that creates a problem especially when you're updating state values because it causes react to render the component again which in turn calls the function again which calls the render again resulting in an infinite loop.

    [16:09 - 16:13] But that's all there is to it. So next it's time to update our button element.

    [16:14 - 16:26] So the button element presents an interesting situation. We need to trigger an update to the display name property however that particular piece of state lives in the app component up here.

    [16:27 - 16:37] So how can we update state from another component? Well in the same way that we can pass data down to child components via the props object we can send data back up using events and event handlers.

    [16:38 - 16:52] To do this we can update our button element with similar looking anonymous arrow function that we used for the input element. But this time instead of calling the function on the app components classes we did previously using this dot handle click we'll call the same function put from our props object.

    [16:53 - 17:11] We'll pass in the up to date value for name from our local state data and that 's the button element finished. So we'll define an arrow function and let's say props dot handle click and we 'll pass in the name value from state there.

    [17:12 - 17:19] So now we need to update the app component. With our three new components complete it's time to edit the app components so we can actually use them.

    [17:20 - 17:35] So first things first let's import our new components at the top of the app component. So we'll import title from the folder components title.

    [17:36 - 17:49] Then we'll import the greeting. And finally we'll import input from components input.

    [17:50 - 17:59] So next we're going to replace the existing JSX with our imported components. Our new return statement should look a lot simpler when we're done.

    [18:00 - 18:11] So we'll replace this. Take out this title and we're going to replace this heading one with our title component.

    [18:12 - 18:20] We're going to replace this line with our greeting. We're going to add just a little line of instructions.

    [18:21 - 18:34] And then we can replace our input and button elements with our input component. Great.

    [18:35 - 18:42] So if you look at the title component you'll see that we've added an attribute of title and passed in the original greeting. Welcome to the app.

    [18:43 - 18:59] This means when our title component calls props.title or references it like we have in the destructuring welcome to the app is what it will receive. We do the same thing with our greeting component but this time we're passing a name attribute the display name value from state using this.distate.display name.

    [19:00 - 19:15] And finally in our input component here we're adding another attribute of handle click which you'll remember needs to be a function so the input component can call it via props. So there are a few more changes to make to the app component before everything is complete.

    [19:16 - 19:22] We can remove the handle change event because it's no longer needed. It's handled within the input component.

    [19:23 - 19:35] We can remove the name property from the state up here because again that's handled in our input component. And we need to update the handle click event here to reference the new name value that's passed to it.

    [19:36 - 19:45] So first things first let's look at the handle change event and just remove it all together. Next we'll update the state object to remove the name property.

    [19:46 - 19:55] So we'll just delete that property out all together. And then lastly we'll update the handle click event to reference the name value that's passed to it from the input component.

    [19:56 - 20:14] So currently it's referencing this EVT object here which is remember the synthetic event object that's passed to it automatically via React. So we can change this to name which will now be a new string value that's passed in when this event is called from within the input component.

    [20:15 - 20:29] Then in the set state method where we're currently passing the property display name the value of this.state.name that we've just deleted. We can update this to use the name argument that is supplied to us from the input components.

    [20:30 - 20:47] So let's give this a save and then let's run this. So you can see not much has changed on the front except now if we type my name and click update.

    [20:48 - 20:51] I can type anything else in here. Update name.

    [20:52 - 21:02] So it doesn't look a lot different but you can see that we're now we've broken down that functionality into smaller moving parts in our separate components. And now the app is using those which is great.

    [21:03 - 21:12] So now we've got to refactor the app component. To round things off we can make a couple more changes to the app component to modernize it a little and make the code a little bit more smaller and a little bit more readable.

    [21:13 - 21:20] So we'll convert the app from a class based component to a functional one. We'll replace the current state mechanism with another use of the use state hook.

    [21:21 - 21:33] So the first thing to do is to convert the class based component the app currently is into a functional one. It might seem a little daunting in this process but it's quite straightforward and it gets easier to do the more you do it.

    [21:34 - 21:42] There are a few main parts to achieve. Firstly we need to replace the class keyword and general class definition up here with a function name and arguments.

    [21:43 - 21:55] Next we'll remove the constructor function altogether which is specific to classes abstracting any logic we need out of here. Then we'll remove this render statement and take the return statement out of it .

    [21:56 - 22:05] Once this is done we can just delete the empty render statement. And finally we'll add the const keyword to any functions that are class properties such as this handle click event here.

    [22:06 - 22:24] So in our case the current app component class declaration and constructor will be replaced up here from this to const app. Get the props object.

    [22:25 - 22:44] And we will do const display name. Set display name equals use state.

    [22:45 - 22:59] And because we're using use state what we need to do is firstly remove this component that we're not component in part that we're no longer using. So we can remove that but replace it with use state that we are currently going to use.

    [23:00 - 23:16] You'll see that we still do need to use the display name property from state which is why we're using the use state hook but notice the naming convention again. We use display name for the value in state and set display name for the name of the function that will update the display name value instead.

    [23:17 - 23:25] We can also remove this entire handle click function here because we'll be replacing it with the set display name function call. Now we can replace the render method.

    [23:26 - 23:41] Because the render method is only needed for class based components we can replace it with the entire return statement. So we can just literally get rid of the render method and that just leaves us with a return statement.

    [23:42 - 23:49] So now the final thing to do is to update our display name instead. So of course now we've updated the display name property to use hooks.

    [23:50 - 24:02] We now need to update our two lines in our return statement. The first isn't a very big change but since we don't have access to a class property named this.state we can just remove it from the greeting and reference display name directly.

    [24:03 - 24:09] So replace this.state.display name with just display name. The very last thing to do is to replace the call to the non-existent this.

    [24:10 - 24:26] handle click that we passed into the input component with a direct call to the hook method set display name. It will receive a name value in an argument and we will just use the set display name directly passing it the name value.

    [24:27 - 24:45] So again to prevent an infinite loop or some other kind of issue we've passed an inline arrow function instead here instead of this.handle click. It receives a name value as an argument when the input component calls this function and we immediately call the set display name function here to update the display name value instead.

    [24:46 - 24:53] And that's everything done. Let's save everything and refresh the page in the browser to see in action and everything should look the way that it did before.

    [24:54 - 25:12] The refactoring process isn't too painful but you can see already how the app components much smaller much neater and much more modular. What's more we now have a bunch of smaller components that contain their very own logic that can be used throughout our app as it grows and starts to expand with more sections.

    [25:13 - 25:27] So we'll just test it out one last time if I type in Superman and click update and they're Superman. Do you react heroes? Well hi there react heroes.