Build Your First Functional React App with Create React App
This code-along lesson walks through using Create React App to build a fully-functioning picture gallery, the Furry Friend Gallery.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo 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.
Get unlimited access to Beginner's Guide to Real World React, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:15] Lesson 4, Building the furry friend gallery. So as we saw in the quick demo of the furry friend gallery, we're going to build an app that talks to our familiar dog CEO, API, loads in a few starter picks before turning control over to the user, allowing them to choose a number of images they're like to fetch.
[00:16 - 00:23] We're going to start by creating a new React project using Create React app. So up until this point, we've been using Parcel JS to set up and configure our React apps.
[00:24 - 00:36] It makes sense for smaller projects or apps, and there's certainly no problem with continuing to choose Parcel for more complex needs. However, out in the realms of real-world commercial environments, you'll often come across React projects with a lot more complexity around their configuration.
[00:37 - 00:56] From employing some static code analysis using tool like ES lint, Beble JS to allow us to use the latest JavaScript features cross browser, and code bundling and optimization with helpful webpack. Create React app is an official React starter project developed and maintained by the Facebook open source team, and it offers all of the above and more in one convenient package with just one dependency.
[00:57 - 01:14] Behind the scenes, a Create React app maintains an up-to-date working configuration that employs modern code and best practices for setting up and working with a React project. It abstracts all of the complex setup required for webpack to bundle your project's files, as well as giving us a list of great code-linting rules to ensure where it's hearing to generally accepted good code standards.
[01:15 - 01:26] What's more, it can be used to spin up a new project and get coding in under five minutes from just a single terminal command. The biggest drawback to using Create React app is also one of its biggest advantages, the abstraction.
[01:27 - 01:38] Many developers and projects demand more flexibility and control from their configuration. By using Create React app, you're effectively handing over control of these parts of your app to the React team and their own development opinions.
[01:39 - 01:52] It's not a bad thing per se, and there are workarounds to add in your own configurations without using the built-in Inject command. Create React app offers this as the last resort should you wish to unbundle all the configurations and improve the dependency on the Create React app itself, but they're not always ideal.
[01:53 - 02:10] For more information about this, and a great guide on how to set up your own React project without Create React app, there's this great article on Dev2 from Nick Hill-Kumran, who you can take a look at. With that out of the way, let's get started with our new gallery app by navigating to your main code project folder on your machine in the terminal.
[02:11 - 02:22] From here, we're going to use the following command to create a brand new React project using the Create React app starter. So we're going to type Yarn, Create React app, and then furry friend gallery.
[02:23 - 02:33] You'll see your terminal command window going to town and pulling in all of the resources that it needs to create a new project. When it's done, you'll have a success message in the terminal featuring a list of commands.
[02:34 - 02:44] Before we do anything else, it's a good idea to jump straight into the new project, launch it, and make sure that it's all working. So follow the advice in the terminal output here and enter the following commands.
[02:45 - 03:01] So we'll cd into furry friend gallery, and then we'll do yarn start. So back in the browser, after a brief couple of moments, you should see a web page open up with a spinning React logo and a simple message.
[03:02 - 03:08] Phew, everything's looking great and our new project almost ready to go. Cleaning up the default files.
[03:09 - 03:17] So Create React app does load in a few bare bones files and styles to give you a jumping off point. However, we'll need to make a few changes to get everything cleaned up and ready for our new gallery app.
[03:18 - 03:27] So first, open in the source folder the index.js. So it's located in the root in source and then remove the following lines.
[03:28 - 03:34] So we'll get rid of this index.css. It should be on line three of this index.js file.
[03:35 - 03:42] This will remove a link to the default styles from the project that we won't need. After that, we'll locate the index.css file and just delete it.
[03:43 - 03:52] Next, find the source app.css file and open it up. Highlight everything in here and delete it and save the file.
[03:53 - 04:04] Finally, open app.js file located in source app.js. And this currently contains a lot of starter JSX that we're going to replace as well as a link to a logo file that we want to remove.
[04:05 - 04:13] So first, locate the following line around line two that imports a logo.svg and remove it. Now select everything in the return statement.
[04:14 - 04:26] Everything between the return, open parenthesis, close parenthesis and replace it with the following. So we'll do our react fragment.
[04:27 - 04:40] Let's put a simple heading one in there, H1 and then welcome to the furry friends gallery. Our project still contains a few default files, components and assets that are loaded in by default.
[04:41 - 04:46] But we're not going to worry about them for now as they're not doing any harm. They're just sitting there and they're not currently being loaded anywhere.
[04:47 - 04:58] And here's where we'll introduce the Bulma CSS Framework. CSS frameworks, much like JavaScript frameworks and libraries such as React itself, allow you to employ some well used and well tested conventions to help you build user interfaces more quickly.
[04:59 - 05:13] CSS frameworks specifically give you access to a design system of sorts, providing many individual elements like buttons and heroes that often combine into larger components, each maintaining the correct look and feel. They also offer some sort of layout system such as a grad or column based layout.
[05:14 - 05:24] We'll be using one frequently throughout this course, the Bulma CSS Framework. I really like Bulma because it's quite lightweight, it's very simple to implement and based on modern CSS using Flexbox for much of its layout options.
[05:25 - 05:34] It can be loaded via an MPM package or simply dropped into a HTML file as an external resource which we'll be doing here. And there is even a React based component library that you can add to your project.
[05:35 - 06:06] I'd recommend taking a look at the Bulma docs available at bulma.io/document ation to familiarize yourself with the elements and components I offer, but for now we'll be adding it to our app using the CSS classes that it gives us to build out our components. Back in our projects in VS Code, our project's going to consist of just three files, app.js, this is where the main action takes place, dogcardinfo.jsx, a reusable list item component that will display each picture, an app.css will need to add a couple of styles in here to tweak the look and feel of our gallery list items.
[06:07 - 06:25] We'll also need to make a single line change in our index.html file that loads the Bulma CSS Framework Forests, so let's start there. So if we navigate to the public folder and index.html and open that file, this is the main starting template.html file that the project uses to render the initial output of the app.
[06:26 - 06:35] It's well commented and you can easily see what every part does. In order to load Bulma so we can take advantage of the styles, we need to add the following line somewhere between the opening and closing head tags.
[06:36 - 06:43] So I'm going to put mine at the bottom, which is referring to the jester liver. net CDN, and we just load in Bulma in there.
[06:44 - 06:52] You can also edit the title of the page between the title tags if you wish. Now it's time to create the dogcardinfo.jsx component.
[06:53 - 07:07] Dogcardinfo will be what's known as a presentational component. That is, it deals with the presentational aspects but usually no logic or very little. A presentational component will accept one or more values as props or direct arguments and simply return a block of JSX to render out.
[07:08 - 07:28] So we'll create a new file in the source directory called dogcardinfo.jsx and we'll drop in the following contents. So you'll see that we're using the destructuring syntax again to break out the image URL and breed values from the props object supplied to this component.
[07:29 - 07:43] The markup here is based on Bulma's card component. The subtle difference here is that we've employed a little image display trick on the figure element. Because the dog images returned from our API are in different sizes and aspect ratios, we can't just drop them directly into the image tag here.
[07:44 - 08:12] Or we could, but rather they'd look wonky and misshapen. What we're doing here is replying the image to the figure element as a background image, which via some styling will take care of next, allows us more control over how things look when the images are weird shapes and sizes. However, in order to keep things nice and semantic and look after those users working with screen readers, we'll use an image tag here with the correct source and alt attributes, but we'll apply a handy helper class, is SR only, that comes with Bulma.
[08:13 - 08:32] Which means the image won't be visible on screen. We're rendering the breed name into the card component div as a nice addition so that people can see what breed they're looking at. So now that we've got our list item display component ready, we'll add a scant handful of styles into the source app.css file, which is loaded in at the top for our app.js file.
[08:33 - 08:48] Nothing too complicated here, but we're adding a height to the main image container from the dogcardinfo.jsx component, otherwise it would collapse because it's child, the image element is hidden. We're also applying some background styles to the child figure element so that the background is sized properly and doesn't repeat.
[08:49 - 09:07] Now it's time to edit the app.js file. So let's start by importing what we need . In our case, the React defaults, our dogcardinfo component and our main styles app.css. So we'll start by importing React, use state and use effect hooks.
[09:08 - 09:16] Now our component, so import dogcardinfo from dogcardinfo. And finally our styles, which are already in.
[09:17 - 09:26] So next, outside of the main app component here, we'll define a new asynchronous function, load dog pictures, which we'll do exactly that. Load a set of pictures from the API.
[09:27 - 09:34] So down here we can say const, load dog pictures. It's going to be an asynchronous function, so we'll use the ASN keyword.
[09:35 - 09:45] It's going to accept a number of dogs to load. Bad default will make that 8. Remember we've added the ASN keyword for our single argument, dog to load, which will also set to a default of 8.
[09:46 - 09:54] So we can specify the number of pictures to fetch from the API, or leave it blank and we'll just get 8 back. Next we'll add our variables.
[09:55 - 10:06] So we have the static API URL, which is the base URL the dog CEO provides for a single random image. We can append this with a number to a maximum of 50 that will return as many images.
[10:07 - 10:22] Next we're using the awake keyword here, which is in front of the fetch command , which will pause the execution of things until the fetch method finishes up returns. Notice how we're using the template literals version of a string here to combine both the base API URL and the number of pictures to fetch.
[10:23 - 10:33] Then we'll perform another await here, as we call the JSON method on response from the API call. This will get as our dog related data in a nice, malleable JSON format ready for doing with as we please.
[10:34 - 10:42] What happens next is some manipulation of the data that's returned to us from the API. In its raw state, the API data will look something like this.
[10:43 - 10:54] So you can see we've got this messages object and a rare of image strings. So we'll need to loop through the image URLs in this message's array, capturing the URL, generating an ID value and working out the breed.
[10:55 - 11:10] To do that, we'll start by using a map to look at each image in turn. We can work out the breed by manipulating the URL string, removing the protocol and splitting the rest of the URL on the forward slash character, and pull the breed from the item in third position in this array.
[11:11 - 11:16] 1, 2, 3. Next we can split the breed string by the dash character and reverse it.
[11:17 - 11:34] For some reason that's how dog CEO people like to log their breed information in reverse name order. Finally, we'll wrap this up by returning an object to this iteration of the map that we populate with a simple generated ID from the index of the image URL in the original list, the image URL and the breed name.
[11:35 - 11:45] Once we have all that, we'll return the array of dog item objects. Now back in the main app component itself, with all good components we're going to start with the variables that we'll be using.
[11:46 - 12:09] Let's define these at the top of the component to be used as we go along. So we've got dog pictures, which will create as an empty array to hold our loaded dog picture objects, is loading to determine if the component is in the process of fetching the dog photos, num of dogs to track the user input and how many pictures they'd like to load, and the total dogs searched, which is a running total of how many pictures have been fetched in total.
[12:10 - 12:16] But we need a way to handle our farm submissions and that's where handle submit function comes in. We'll define that next.
[12:17 - 12:27] So first we prevent the farm from causing a page reload. That'll just kill off our app's functionality by calling the e, it's a synthetic event, the e.prevent default.
[12:28 - 12:39] Then we toggle the is loading state value to true, which will be used later to set some visibility on some of our UI elements. And once we're loading, we'll trigger a fetch from the API via the load dog pictures function.
[12:40 - 12:48] And last but not least, we'll need to toggle is loading back to false once we have our pictures. Now notice the use of JavaScript's built in async await pairing in this function.
[12:49 - 12:57] If you have an async there, and then we call the main async credits function, we apply the await keyword. This is where things get a little more interesting.
[12:58 - 13:03] We're going to be using two separate calls to the user effect hook to handle two side effects. So let's deal with the first.
[13:04 - 13:15] We call user effect, pass it an anonymous arrow function, and then we define our dependency array. So we're going to call set total dog searched.
[13:16 - 13:31] In the dependency array, we will add the dog pictures variable from up there. So this hook is just one line, but you'll notice that we've passed in dog pictures into the dependency array.
[13:32 - 13:52] What we're saying here is when dog pictures changes, execute whatever code is inside of the user effect hook. Inside of the body of the function, we're setting the total dog search value instead to the current value, plus the length of the new array of pictures that we'll have when the value of dog pictures changes.
[13:53 - 14:05] You might be wondering about the unusual way in which we've called the set total dog search function to update the total dog search value instead. Previously, we've just passed in the new value you wish to have, and that's the way you usually do things.
[14:06 - 14:17] However, if we did that here, although that would technically work, we'd be breaking one of the rules of hooks, and you'd most likely get an ESLint error that sounds like this. React hook user effect has a missing dependency.
[14:18 - 14:31] Because we're referencing a value from our component, in this case the state value total dog searched, but not including it in the list of dependencies that have passed to the user effect, we get this error. It's a potential problem because we run the risk of using stale data.
[14:32 - 14:41] Each time the component updates, changes or re-renders, the value of total dog searched could be different. We're referencing that value, and so you can see how it could cause problems.
[14:42 - 14:56] However, if we include it in the dependencies array here, we'll most likely run into an infinite loop, because this effect will then be called when dog pictures or total dog search changes. But of course, we are changing total dog searched, so we can update our UI.
[14:57 - 15:15] So every time it changes, we call the set total dog search function to update it, then the effect runs again, and again, and so on until our app stops working. The basic rule of thumb is that if you are going to reference a function or a value from state or props inside of user effect, then you must include it in the dependency array.
[15:16 - 15:25] There's lots more information available on the subject if you head over to the official React documentation. For us, however, we can fix this by using the functional form of the state update method.
[15:26 - 15:45] So instead of passing a direct value into the set total dog searched function to update the value instead here, we can just pass it a function, which will receive the current value from state as an argument. This fixes the potential stale data error that we might run into and doesn't run file of the hook's rules.
[15:46 - 15:55] Now we need to define one last use of our user effect hook that we'll call with an empty dependency array, so that it's only triggered on first component mount. Let's do that next.
[15:56 - 16:07] In here, we'll need to make sure that we kick off an initial load of some dog pictures to populate our app with. Once that's defined, you'll see that we're using the same form of functional update for setting various state values here.
[16:08 - 16:23] We're going to wrap all of these updates in a self-executing anonymous function , otherwise known as an immediately invoked function expression, that implies the async await syntax. We could have just defined a regular function in here too, and then immediately called it, and that would work just fine.
[16:24 - 16:30] I've just gone with personal preference here and opted for a simpler syntax. And finally, for the JSX markup.
[16:31 - 16:38] What would a component be without returning some markup to render our UI? Define a simple return statement with a container div element.
[16:39 - 16:54] And in here, we'll need two sections, one for the search form and another to render the dog pictures. So first, let's define the header and search form.
[16:55 - 17:11] Notice the few extra divs and class names from Bulma. We've attached the handle submit function to the form, and wired up the input element's value to the num_dog's value instead, as well as adding an inline state update in the onChange event here.
[17:12 - 17:21] They will update the value whenever a user enters some text. The button element in this section here just serves to trigger the submission of the form.
[17:22 - 17:42] The picture display section will look something like this, so after our header, we have a heading level 3 element, that will display the total number of pictures search for using the total dog search value instead. Next, we'll show an animated progress bar if the is loading value is set to true.
[17:43 - 17:58] So if this is true, it evaluates the right hand side of the expression and displays a progress bar. However, if the is loading value is false, we'll map over the dog pictures array instead, returning a new dog card info component for each item in the array.
[17:59 - 18:13] This component is wrapped in a div with a column class, so that it will automatically render them side by side in the UI. Viewing our hard work. With everything typed up and set to go, that just leaves us to have a final check through to make sure everything is working as it should.
[18:14 - 18:27] Over in our terminal, we can type " yarn start". And if everything is gone to plan, we should have a great looking site that shows there's nothing but some well-behaved dogs doing what they do best.
[18:28 - 18:43] So you can see we've loaded in 8 pictures by default, and if you want to look for 3, then do a search. You can see we just got 3 back. We've already found 11 in total, and if we search for 10, do a search.
[18:44 - 18:53] You can see that we get 10 dog pictures back. All good looking chaps. And then we update the total dog search for to 21 so far.
[18:54 - 19:02] >> Okay.