Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
React Projects
React Projects

React Projects: Build advanced cross-platform projects with React and React Native to become a professional developer , Second Edition

eBook
zł59.99 zł125.99
Paperback
zł157.99
Subscription
Free Trial

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Table of content icon View table of contents Preview book icon Preview Book

React Projects

Chapter 2: Creating a Portfolio in React with Reusable Components and Routing

Do you already feel familiar with React's core concepts after completing the first chapter? Great! This chapter will be no problem for you! If not, don't worry – most of the concepts you came across in the previous chapter will be repeated. However, if you want to get more experience with Webpack and Babel, it's recommended that you try creating the project in Chapter 1, Creating a Single-Page Application in React, again since this chapter won't be covering those topics.

In this chapter, you'll work with Create React App, a starter kit created by the React core team to get you started with React quickly. It will make the configuration of module bundlers and compilers such as Webpack and Babel unnecessary, as this will be taken care of by the Create React App package. This means you can focus on building your portfolio application, which reuses React components and has routing. Besides that, we'll be adding routing using react-router v6, which is the leading library for routing in React.

Alongside setting up Create React App, the following topics will be covered in this chapter:

  • Creating a new project with Create React App
  • Building reusable React components
  • Routing with react-router

Can't wait? Let's go!

Project overview

In this chapter, we will create an application with React that makes use of reusable React components and styling using Create React App and styled-components. The application will use data that is fetched from the public GitHub API.

The build time is 1.5–2 hours.

Getting started

The project you'll create in this chapter will use the public API from GitHub, which you can find at https://docs.github.com/en/rest. To use this API, you need to have a GitHub account, since you'll want to retrieve information from a GitHub user account. If you don't have a GitHub account yet, you can create one on the GitHub website. The complete source code for this application can also be found on GitHub: https://github.com/PacktPublishing/React-Projects-Second-Edition/tree/main/Chapter02.

Creating a portfolio in React

In this section, we will learn how to create a new React project using Create React App and add reusable React components and routing with react-router.

Creating a portfolio with Create React App

Having to configure Webpack and Babel every time we create a new React project can be quite time-consuming. Also, the settings for every project can change, and it becomes hard to manage all of these configurations when we want to add new features to our project.

Therefore, the React core team introduced a starter kit known as Create React App, which is currently at version 5. By using Create React App, we no longer have to worry about managing compile and build configurations, even when newer versions of React are released, which means we can focus on coding instead of configurations.

This section will show us how to create a React application with Create React App.

Before anything else, let's see how to install Create React App.

Installing Create React App

Create React App doesn't have to be installed globally. Instead, we can use npx, a tool that comes preinstalled with npm (v5.2.0 or higher) and simplifies the way that we execute npm packages:

npx create-react-app chapter-2

This will start the installation process for Create React App, which can take several minutes, depending on your hardware. Although we're only executing one command, the installer for Create React App will install the packages we need to run our React application. Therefore, it will install react, react-dom, and react-scripts, where the last package includes all the configurations for compiling, running, and building React applications.

If we move into the project's root directory, which is named after our project name, we will see that it has the following structure:

chapter-2
  |- node_modules
  |- package.json
  |- public
     |- index.html
  |- src
     |- App.css
     |- App.test.js
     |- App.js
     |- index.css
     |- index.js

Note

Not all files that were created by Create React App are listed; instead, only the ones used in this chapter are listed.

This structure looks a lot like the one we set up in the first chapter, although there are some slight differences. The public directory includes all the files that shouldn't be included in the compile and build process, and the files inside this directory are the only files that can be directly used inside the index.html file.

In the other directory, called src, we will find all the files that will be compiled and built when we execute any of the scripts inside the package.json file. There is a component called App, which is defined by the App.js, App.test.js, and App.css files, and a file called index.js, which is the entry point for Create React App.

If we open the package.json file, we'll see that four scripts have been defined: start, build, test, and eject. Since the last two aren't handled at this point, we can ignore these two scripts for now. To be able to open the project in the browser, we can simply type the following command into the command line, which runs package react-scripts in development mode:

npm start

Note

Instead of npm start, we can also run yarn start, as using Yarn is recommended by Create React App.

If we visit http://localhost:3000/, the default Create React App page will look as follows:

Figure 2.1 – The default Create React App boilerplate

Figure 2.1 – The default Create React App boilerplate

Since react-scripts supports hot reloading by default, any changes we make to the code will result in a page reload. If we run the build script, a new directory called build will be created in the project's root directory, where the minified bundle of our application can be found.

With the basic installation of Create React App in place, we will start looking at creating the components for our project and styling them.

Building reusable React components

Creating React components with JSX was briefly discussed in the previous chapter, but in this chapter, we'll explore this topic further by creating components that we can reuse throughout our application. First, let's look at how to structure our application, which builds upon the contents of the previous chapter.

Structuring our application

Our project still consists of only one component, which doesn't make it very reusable. To begin, we'll need to structure our application in the same way that we did in the first chapter. This means that we need to split up the App component into multiple smaller components. If we look at the source code for this component in App.js, we'll see that there's already a CSS header element in the return function. Let's change that header element into a React component:

  1. First, create a new file called Header.css inside a new directory called components within src and copy the styling for classNames, App-header, App-logo, and App-link into it:
    .App-logo {
      height: 40vmin;
      pointer-events: none;
    }
    @media (prefers-reduced-motion: no-preference) {
      .App-logo {
        animation: App-logo-spin infinite 20s linear;
      }
    }
    .App-header {
      background-color: #282c34;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-size: calc(10px + 2vmin);
      color: white;
    }
    .App-link {
      color: #61dafb;
    }
    @keyframes App-logo-spin {
      from {
        transform: rotate(0deg);
      }
      to {
        transform: rotate(360deg);
      }
    }
  2. Now, create a file called Header.js inside this directory. This file should return the same content as the <header> element:
    import './Header.css';
    function Header() {
      return (
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo'
          />
          <p>Edit <code>src/App.js</code> 
            and save to reload. </p>
          <a
            className='App-link'
            href='https://reactjs.org'
            target='_blank'
            rel='noopener noreferrer'
          >
            Learn React
          </a>
        </header>
      );
    }
    export default Header;
  3. Import this Header component inside your App component and add it to the return function:
    + import Header from './components/Header';
      import './App.css';
      import logo from './logo.svg';
      function App() {
        return (
          <div className="App">
    -       <header className='App-header'>
    -        <img src={logo} className='App-logo'
               alt='logo' />
    -        <p>Edit <code>src/App.js</code> and save to
               reload. </p>
    -        <a
    -          className='App-link'
    -          href='https://reactjs.org'
    -          target='_blank'
    -          rel='noopener noreferrer'
    -        >
    -         Learn React
    -       <a>
    -     </header>
    +     <Header />
        </div>
      );
    }
    export default App;

The styles for the header need to be deleted from App.css. This file should only contain the following style definitions:

.App { 
  text-align: center; 
} 
.App-link { 
  color: #61dafb; 
}

When we visit our project in the browser again, we'll see an error saying that the value for the logo is undefined. This is because the new Header component can't reach the logo constant that's been defined inside the App component. From what we learned in the first chapter, we know that this logo constant should be added as a prop to the Header component so that it can be displayed. Let's do this now:

  1. Send the logo constant as a prop to the Header component in src/App.js:
    // ...
    function App() {
       return (
         <div className='App'>
    -      <Header />
    +      <Header logo={logo} />
         </div>
       );
     }
    }
    export default App;
  2. Get the logo prop so that it can be used by the img element as an src attribute in src/components/Header.js:
      import './Header.css';
    - function Header() {
    + function Header({ logo }) {
        return (
          <header className='App-header'>
            // ...

Here, we won't see any visible changes when we open the project in the browser. But if we open up the React Developer Tools, we will see that the project is now divided into an App component and a Header component. This component receives the logo prop in the form of a .svg file, as shown in the following screenshot:

Figure 2.2 – The React Developer Tools

Figure 2.2 – The React Developer Tools

The Header component is still divided into multiple elements that can be split into separate components. Looking at the img and p elements, they look pretty simple already. However, the a element looks more complicated and takes attributes such as url, title, and className. To change this a element into a component we can reuse, it needs to be moved to a different location in our project.

To do this, create a new file called Link.js inside the components directory. This file should return the same a element that we've already got inside our Header component. Also, we can send both url and title to this component as a prop. Let's do this now:

  1. Delete the styling for the App-link class from src/components/Header.css and place this inside a file called Link.css:
    .App-link {
        color: #61dafb;
    }
  2. Create a new component called Link that takes the url and title props. This component adds these props as attributes to the <a> element in src/components /Link.js:
    import './Link.css';
    function Link({ url, title }) {
      return (
        <a
          className='App-link'
          href={url}
          target='_blank'
          rel='noopener noreferrer'
        >
          {title}
        </a>
      );
    };
    export default Link;
  3. Import this Link component and place it inside the Header component in src/components/Header.js:
    + import Link from './Link.js';
      import './Header.css';
      function Header({ logo }) {
        return (
          <header className='App-header'>
            <img src={logo} className='App-logo'
              alt='logo' />
            <p>Edit <code>src/App.js</code> and save to 
              reload. </p>
    -       <a
    -         className='App-link'
    -         href='https://reactjs.org'
    -         target='_blank'
    -         rel='noopener noreferrer'
    -        >
    -          Learn React
    -       <a>
    +       <Link 
    +         url='https://reactjs.org'
    +         title='Learn React' 
    +        />
        </header>
      );
    }
    export default Header;
  4. Our code should now look like the following, meaning that we've successfully split the App component into different files in the components directory. Also, the logo.svg file can be moved to a new directory called assets:
    chapter-2
      |- node_modules
      |- package.json
      |- public
         |- index.html
      |- src
         |- assets
            |- logo.svg
         |- components
            |- Header.css
            |- Header.js
            |- Link.css
            |- Link.js
         |- App.css
         |- App.js 
         |- index.css
         |- index.js
  5. Don't forget to also change the import statement in the src/App.js file, where the logo.svg file is imported as a component:
      import Header from './components/Header';
      import './App.css';
    - import logo from './logo.svg';
    + import logo from './assets/logo.svg';
      function App() {
        return (
          // ...

However, if we take a look at the project in the browser, no visible changes are present. In the React Developer Tools, however, the structure of our application has already taken shape. The App component is shown as the parent component in the component tree, while the Header component is a child component that has Link as a child.

In the next part of this section, we'll add more components to the component tree of this application and make these reusable throughout the application.

Reusing components in React

The project we're building in this chapter is a portfolio page; it will show our public information and a list of public repositories. Therefore, we need to fetch the official GitHub REST API (v3) and pull information from two endpoints. Fetching data is something we did in the first chapter, but this time, the information won't come from a local JSON file. The method to retrieve the information is almost the same. We'll use the fetch API to do this.

We can retrieve our public GitHub information from GitHub by executing the following command (replace username at the end of the bold section of code with your own username):

curl 'https://api.github.com/users/username'

Note

If you don't have a GitHub profile or haven't filled out all the necessary information, you can also use the octocat username. This is the username of the GitHub mascotte and is already filled with sample data.

This request will return the following output:

{
  "login": "octocat",
  "id": 583231,
  "node_id": "MDQ6VXNlcjU4MzIzMQ==",
  "avatar_url": 
    "https://avatars.githubusercontent.com/u/583231?v=4",
  "gravatar_id": "",
  "url": "https://api.github.com/users/octocat",
  "html_url": "https://github.com/octocat",
  "followers_url":
    "https://api.github.com/users/octocat/followers",
  "following_url":
    "https://api.github.com/users/octocat/following{
      /other_user}",
  "gists_url": 
    "https://api.github.com/users/octocat/gists{/gist_id}",
  "starred_url":
    "https://api.github.com/users/octocat/starred{/owner}{
      /repo}",
  "subscriptions_url": 
    "https://api.github.com/users/octocat/subscriptions",
  "organizations_url":
    "https://api.github.com/users/octocat/orgs",
  "repos_url":
    "https://api.github.com/users/octocat/repos",
  "type": "User",
  "site_admin": false,
  "name": "The Octocat",
  "company": "@github",
  "blog": "https://github.blog",
  "location": "San Francisco",
  "email": null,
  "hireable": null,
  "bio": null,
  "twitter_username": null,
  "public_repos": 8,
  "public_gists": 8,
  "followers": 3555,
  "following": 9
}

Multiple fields in the JSON output are highlighted, since these are the fields we'll use in the application. These are avatar_url, html_url, repos_url, name, company, location, email, and bio, where the value of the repos_url field is actually another API endpoint that we need to call to retrieve all the repositories of this user. This is something we'll do later in this chapter.

Since we want to display this result in the application, we need to do the following:

  1. To retrieve this public information from GitHub, create a new component called Profile inside a new directory called pages. This directory will hold all the components that represent a page in our application later on. In this file, add the following code to src/pages/Profile.js:
    import { useState, useEffect } from 'react';
    function Profile({ userName }) {
      const [loading, setLoading] = useState(false);
      const [profile, setProfile] = useState({});
      useEffect(() => {
        async function fetchData() {
          const profile = await fetch(
            'https://api.github.com/users/${userName}');
          const result = await profile.json();
          if (result) {
            setProfile(result);
            setLoading(false);
          }
        }
        fetchData();
      }, [userName]);
      return (
        <div>
          <h2>About me</h2>
          {loading ? (
            <span>Loading...</span>
          ) : (
            <ul></ul>
          )}
        </div>
       );
    }
    export default Profile;

This new component imports two Hooks from React, which are used to handle state management and life cycles. We've already used a useState Hook in the previous chapter, and it's used to create a state for loading and profile. Inside the second Hook, which is the useEffect Hook, we do the asynchronous data fetching from the GitHub API. No result has been rendered yet, since we still need to create new components to display the data.

  1. Now, import this new component into the App component and pass the userName prop to it. If you don't have a GitHub account, you can use the username octocat:
      import Header from './Header';
    + import Profile from './pages/Profile';
      import './App.css';
      function App() {
        return (
          <div className='App'>
            <Header logo={logo} />
    +       <Profile userName="octocat" />
          </div>
        );
      }
    }
    export default App;
  2. A quick look at the browser where our project is running shows that this new Profile component isn't visible yet. This is because the Header.css file has a height attribute with a view-height value of 100, meaning that the component will take up the entire height of the page. To change this, open the src/components/Header.css file and change the following highlighted lines:
      .App-logo {
    -   height: 40vmin;
    +   height: 60px;
        pointer-events: none;
      }
      // ... 
      .App-header {
        background-color: #282c34;
    -   min-height: 100vh;
    +   min-height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-size: calc(10px + 2vmin);
        color: white;
      }
  3. There should be enough free space on our page to display the Profile component, so we can open the scr/pages/Profile.js file once more and display the avatar_url, html_url, repos_url, name, company, location, email, and bio fields that were returned by the GitHub API:
      // ...
      return (
        <div>
          <h2>About me</h2> 
          {loading ? (
            <span>Loading...</span>
          ) : (
            <ul>
    +         <li><span>avatar_url: </span>
                {profile.avatar_url}</li>
    +         <li><span>html_url: </span> 
                {profile.html_url}</li>
    +         <li><span>repos_url: </span> 
                {profile.repos_url}</li>
    +         <li><span>name: </span> {profile.name}</li>
    +         <li><span>company: </span>
                {profile.company}</li>
    +         <li><span>location: </span>
                {profile.location}</li>
    +         <li><span>email: </span>
                {profile.email}</li>
    +         <li><span>bio: </span> {profile.bio}</li>
            </ul>
          )}
        </div>
      );
    }
    export default Profile;

Once we've saved this file and visited our project in the browser, we will see a bullet list of the GitHub information being displayed.

Since this doesn't look very pretty and the header doesn't match the content of the page, let's make some changes to the styling files for these two components:

  1. Change the code for the Header component so that it will display a different title for the page. Also, the Link component can be deleted from here, as we'll be using it in a Profile component later on:
      import './Header.css';
    - import Link from './Link';
      function Header({ logo }) {
        return (
          <header className='App-header'>
            <img src={logo} className='App-logo'
             alt='logo' />
    -       <p>
    -         Edit <code>src/App.js</code> and save to
                reload.
    -       </p>
    -       <Link url='https://reactjs.org' 
              title='Learn React' />
    +       <h1>My Portfolio</h1>
          </header>
        );
      }
      export default Header;
  2. Before changing the styling of the Profile component, we first need to create a CSS file that will hold the styling rules for the component. To do so, create the Profile.css file in the pages directory and add the following content:
    .Profile-container {
      width: 50%;
      margin: 10px auto;
    }
    .Profile-avatar {
      width: 150px;
    }
    .Profile-container > ul {
      list-style: none;
      padding: 0;
      text-align: left;
    }
    .Profile-container > ul > li {
      display: flex;
      justify-content: space-between;
    }
    .Profile-container > ul > li > span {
      font-weight: 600;
    }
  3. In src/pages/Profile.js, we need to import this file to apply the styling. Remember the Link component we created previously? We also import this file, as it will be used to create a link to our profile and a list of repositories on the GitHub website:
      import { useState, useEffect } from 'react';
    + import Link from '../components/Link';
    + import './Profile.css';
      function Profile({ userName }) {
        
        // ..
  4. In the return statement, we'll add the classNames function that we defined in the styling and separate the avatar image from the bullet list. By doing that, we also need to wrap the bullet list with an extra div:
      // ...
      return (
    -   <div>
    +   <div className='Profile-container'>    
          <h2>About me</h2>
          {loading ? (
            <span>Loading...</span>
          ) : (
    +       <div>
    +         <img
    +           className='Profile-avatar'
    +           src={profile.avatar_url}
    +           alt={profile.name}
    +         />
              <ul>
    -           <li><span>avatar_url: </span>
                  {profile.avatar_url}</li>
    -           <li><span>html_url: </span>
                  {profile.html_url}</li>
    -           <li><span>repos_url: </span>
                  {profile.repos_url}</li>
    +           <li>
    +             <span>html_url: </span>
    +             <Link url={profile.html_url}
                   title={profile.html_url} />
    +           </li>
    +           <li>
    +             <span>repos_url: </span>
    +             <Link url={profile.repos_url} 
                    title={profile.repos_url} />
    +           </li>
                <li><span>name: </span>
                  {profile.name}</li>
                <li><span>company: </span>
                  {profile.company}</li>
                <li><span>location: </span>
                  {profile.location}</li>
                <li><span>email: </span>
                  {profile.email}</li>
                <li><span>bio: </span> {profile.bio}</li>
             </ul>
    +      </div>
         );
       }
       // ..

Finally, we can see that the application is starting to look like a portfolio page loading your GitHub information, including your avatar and a list of the public information. This results in an application that looks similar to what's shown in the following screenshot:

Figure 2.3 – Our styled portfolio application

Figure 2.3 – Our styled portfolio application

If we take a look at the code in the Profile component, we'll see that there is a lot of duplicate code, so we need to transform the list that's displaying our public information into a separate component. Let's get started:

  1. Create a new file called List.js inside the components directory, which will take a prop called items:
    function List({ items }) {
      return (
        <ul></ul>
      );
    }
    export default List;
  2. In the Profile component, we can import this new List component. A new variable called items should be created, which is an array containing all the items we want to display inside this list:
      import { useState, useEffect } from 'react';
    + import List from '../components/List';
      import Link from '../components/Link';
      import './Profile.css';
      function Profile({ userName }) {
        // …
    +   const items = [
    +     {
    +       field: 'html_url',
    +       value: <Link url={profile.html_url} 
              title={profile.html_url} />,
    +     },
    +     {
    +       field: 'repos_url',
    +       value: <Link url={profile.repos_url}
              title={profile.repos_url} />,
    +     },
    +     { field: 'name', value: profile.name },
    +     { field: 'company', value: profile.company },
    +     { field: 'location', value: profile.location },
    +     { field: 'email', value: profile.email },
    +     { field: 'bio', value: profile.bio },
    +   ];
        // ...
  3. This will be sent as a prop to the List component, so these items can be rendered from that component instead. This means that you can remove the ul element and all the li elements inside:
        // ...  
        return (
          <div className='Profile-container'>
            <h2>About me</h2>
            {loading ? (
              <span>Loading...</span>
            ) : (
              <div>
                <img
                  className='Profile-avatar'
                  src={profile.avatar_url}
                  alt={profile.name}
                />
    -           <ul>
    -             // ...
    -           </ul>
    +           <List items={items} />
              </div>
            )}
          </div>
        );
      }
    export default Profile;

You can see that for the list item with the html_url and repos_url fields, we'll be sending the Link component as a value instead of the value that was returned from the GitHub API. In React, you can also send complete components as a prop to a different component, as props can be anything.

  1. In the List component, we can now map over the items prop and return the list items:
      // ...
      function List({ items }) {
        return (
          <ul>
    +       {items.map((item) => (
    +         <li key={item.field}>
    +           <span>{item.field}: </span>
    +           {item.value}
    +         </li>
    +       ))}
          </ul>
        );
      }
      export default List;

The styling is inherited from the Profile component, as the List component is a child component. To structure your application better, you can move the styling for the list of information to a separate List.css file and import it inside the List component.

Assuming we executed the preceding steps correctly, your application shouldn't have changed aesthetically. However, if we take a look at the React Developer Tools, we will see that some changes have been made to the component tree.

In the next section, we'll add routing with react-router and display repositories that are linked to our GitHub account.

Routing with react-router

react-router v6 is the most popular library in React for routing, and it supports lots of features to help you get the most out of it. With this library, you can add declarative routing to a React application, just by adding components. These components can be divided into three types: router components, route matching components, and navigation components.

Setting up routing with react-router consists of multiple steps:

  1. To use these components, you need to install the react-router web package, called react-router-dom, by executing the following:
    npm install react-router-dom
  2. After installing react-router-dom, the next step is to import the routing and route matching components from this package into the container component of your application. In this case, that is the App component, which is inside the src directory:
      import React from 'react';
    + import { BrowserRouter, Routes, Route } 
        from 'react-router-dom';
      import logo from './assets/logo.svg';
      import './App.css';
      import Header from './components/Header';
      import Profile from './pages/Profile';
      function App() {
        // …
  3. The actual routes must be added to the return statement of this component, where all of the route matching components (Route) must be wrapped in a routing component, called Router. When your URL matches a route defined in any of the iterations of Route, this component will render the React component that passed as a child:
      // ...
      function App() {
        return (
          <div className='App'>
    +       <BrowserRouter>
            <Header logo={logo} />
    -         <Profile userName='octocat' />
    +         <Routes>
    +           <Route 
    +             path='/'
    +             element={<Profile userName='octocat' />}
    +           />
    +         </Routes>
    +       </BrowserRouter>
          </div>
        );
      }
      export default App;

If you now visit the project in the browser again at http://localhost:3000, the Profile component will be rendered.

Besides our GitHub profile, we also want to showcase the projects we've been working on. Let's add a new route to the application, which will render all the repositories of our GitHub account:

  1. This new component will use the endpoint to get all your repositories, which you can try out by executing the following command (replace username at the end of the bold section of code with your own username):
    curl 'https://api.github.com/users/username/repos'

The output of calling this endpoint will look something like this:

[
  {
    "id": 132935648,
    "node_id": "MDEwOlJlcG9zaXRvcnkxMzI5MzU2NDg=",
    "name": "boysenberry-repo-1",
    "full_name": "octocat/boysenberry-repo-1",
    "private": false,
    "html_url":
      "https://github.com/octocat/boysenberry-repo-1",
    "description": "Testing",
    "fork": true,
    "created_at": "2018-05-10T17:51:29Z",
    "updated_at": "2021-01-13T19:56:01Z",
    "pushed_at": "2018-05-10T17:52:17Z",
    "stargazers_count": 9,
    "watchers_count": 9,
    "forks": 6,
    "open_issues": 0,
    "watchers": 9,
    "default_branch": "master"
  },
  // ...
]

As you can see from the preceding sample response, the repositories data is an array with objects. We'll be using the preceding highlighted fields to display our repositories on the /projects route.

  1. First, we need to create a new component called Projects in the pages directory. This component will have almost the same logic for state management and data fetching as the Profile component, but it will call a different endpoint to get the repositories instead:
    import { useState, useEffect } from 'react';
    import Link from '../components/Link';
    import List from '../components/List;
    function Projects({ userName }) {
      const [loading, setLoading] = useState(true);
      const [projects, setProjects] = useState({});
      useEffect(() => {
        async function fetchData() {
          const data = await fetch(
           'https://api.github.com/users/${
            userName}/repos',
          );
          const result = await data.json();
          if (result) {
            setProjects(result);
            setLoading(false);
          }
        }
        fetchData();
      }, [userName]);
      
      // ...
  2. After putting the information from the endpoint to the local state variable projects, we'll use the same List component to render the information about the repositories:
      // ...
      return (
        <div className='Projects-container'>
          <h2>Projects</h2>
          {loading ? (
            <span>Loading...</span>
          ) : (
            <div>
              <List items={projects.map((project) => ({
                field: project.name,
                value: <Link url={project.html_url}
                title={project.html_url} />,
      }))} />
            </div>
          )}
        </div>
      );
    }
    export default Projects;
  3. To have this component render when we visit the /profile route, we need to add it to the App component using a Route component:
      import React from 'react';
      import { BrowserRouter, Routes, Route } 
        from 'react-router-dom';
      import logo from './assets/logo.svg';
      import './App.css';
      import Header from './components/Header';
      import Profile from './pages/Profile';
    + import Projects from './pages/Projects';
      function App() {
        return (
          <div className='App'>
            <Header logo={logo} />
            <BrowserRouter>
              <Routes>
                <Route path='/' element={  <Profile
                   userName='octocat' />} />
    +           <Route path='/projects' element=
                     {<Projects userName='octocat' />} />
                </Routes>
              </BrowserRouter>
            // ...

The Profile component will now only be rendered if you visit the / route, and the Projects component when you visit the /projects route. No component will be rendered besides the Header component if you visit any other route.

Note

You can set a component that will be displayed when no route can be matched by passing * as a path to the Route component.

Although we have two routes set up, the only way to visit these routes is by changing the URL in the browser. With react-router, we can also create dynamic links to visit these routes from any component. In our Header component, we can add a navigation bar that renders links to these routes:

  import './Header.css';
+ import { Link as RouterLink } from 'react-router-dom';
  function Header({ logo }) {
    return (
      <header className='App-header'>
        <img src={logo} className='App-logo' alt='logo' />
        <h1>My Portfolio</h1>
+       <nav>
+         <RouterLink to='/' className='App-link'>
+           About me
+         </RouterLink>
+         <RouterLink to='/projects' className='App-link'>
+           Projects
+         </RouterLink>
+       </nav>
      </header>
    );
  }
  export default Header;

As we already have a Link component defined ourselves, we're importing the Link component from react-router-dom as RouterLink. This will prevent confusion if you make any changes later on, or when you're using an autocomplete feature in your IDE.

Finally, we can add some styling to Header.css so that the links to our routes are displayed nicely:

  .App-header {
    background-color: #282c34;
    min-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: calc(10px + 2vmin);
    color: white;
  }
+ .App-header > nav {
+   margin-bottom: 10px;
+ }
+ .App-header > nav > .App-link {
+   margin-right: 10px;
+ }

If you now visit the application in the browser at http://localhost:3000/projects, it should look something like the following screenshot. Clicking on the links in the header will navigate you between the two different routes:

Figure 2.4 – The Projects route in our application

Figure 2.4 – The Projects route in our application

With these routes in place, even more routes can be added to the router component. A logical one is having a route for individual projects, which has an extra parameter that specifies which projects should be displayed. Therefore, we have a new component called the ProjectDetailpages directory, which contains the logic for fetching an individual repository from GitHub API. This component is rendered when the path matches /projects/:name, where name stands for the name of the repository that is clicked on on the projects page:

  1. This route uses a new component in a file called ProjectDetail.js, which is similar to the Projects component. You can also create this file in the pages directory, except that it will be fetching data from the https://api.github.com/repos/userName/repo endpoint, where userName and repo should be replaced with your own username and the name of the repository that you want to display:
    import { useState, useEffect } from 'react';
    Import { useParams } from 'react-router-dom';
    function Project({ userName }) {
      const [loading, setLoading] = useState(false);
      const [project, setProject] = useState([]);
      const { name } = useParams();
      useEffect(() => {
        async function fetchData() {
          const data = await fetch(
            'https://api.github.com/repos/${
             userName}/${name}',
          );
          const result = await data.json();
          if (result) {
            setProject(result);
            setLoading(false);
          }
        }
        if (userName && name) {
          fetchData();
        }
      }, [userName, name]);
      // ...

In the preceding section, you can see how the data is retrieved from the GitHub API, using both your username and the name of the repository. The name of the repository comes from the useParams Hook from react-router-dom, which gets the name variable from the URL for you.

  1. With the repository data retrieved from GitHub, you can create the items variable that is used to render information about this project using the List component that we also used in the previous routes. The fields that are added to items are coming from GitHub and can also be seen in the response of the https://api.github.com/users/username/repos endpoint that we inspected previously. Also, the name of the repository is listed previously:
     // ...
      return (
        <div className='Project-container'>
          <h2>Project: {project.name}</h2>
          {loading ? (
            <span>Loading...</span>
          ) : (
            <div></div>
          )}
        </div>
      );
    }
    export default Project;
  2. To render this component on the /projects/:name route, we need to add this component within the Router component inside App.js:
      // ...
    + import ProjectDetail from './pages/ProjectDetail';
      function App() {
        return (
          <div className='App'>
            <BrowserRouter>
              <Header logo={logo} />
              <Routes>
                <Route exact path='/' element=
                  {<Profile userName='octocat' />} />
                <Route path='/projects' elements=
                  {<Projects userName='octocat' />} />
    +           <Route path='/projects/:name' element=
                  {<ProjectDetail userName='octocat' />} 
                />
            </Routes>
          </BrowserRouter>
        );
      }
  3. You can already navigate to this route by changing the URL in the browser, but you also want to add a link to this page in the Projects component. Therefore, you need to make changes that will import RouterLink from react-router-dom and use it instead of your own Link component:
      import { useState, useEffect } from 'react';
    + import { Link as RouterLink } from 
        'react-router-dom'
      import List from '../components/List';
    - import Link from '../components/Link';
      // ...
      return (
        <div className='Projects-container'>
          <h2>Projects</h2>
          {loading ? (
            <span>Loading...</span>
          ) : (
            <div>
              <List items={projects.map((project) => ({
                field: project.name,
    -           value: <Link url={project.html_url}
                title={project.html_url} />,
                  }))items} />
    +           value: <RouterLink url={project.html_url}
                title={project.html_url} />,
                  }))items} />
            </div>
          )}
        </div>
      );
    }
    export default Projects;

If you now visit the http://localhost:3000/projects page in the browser, you can click on the projects and move on to a new page that shows all the information for a specific project.

With these last changes, you've created a portfolio application that uses react-router for dynamic routing.

Summary

In this chapter, you used Create React App to create your starter project for a React application, which comes with an initial configuration for libraries such as Babel and Webpack. By doing this, you don't have to configure these libraries yourself and worry about how your React code will run in the browser. We've looked into building reusable components in this chapter and learned how to add dynamic routing with react-router. With this library, you can create applications that have tons of routes, and you're able to use changes in the URL to change what is displayed inside your application.

The upcoming chapters will all feature projects that are created with Create React App or other zero-config libraries, meaning that these projects don't require you to make changes to Webpack or Babel.

In the next chapter, we will build upon this chapter by creating a dynamic project management board with React that uses styled-components for styling and reuses logic with custom Hooks.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Build React applications at scale using React patterns and best practices
  • Explore React features such as Hooks, the Context API, and the Suspense API
  • Extend React’s integration with React Native for building cross-platform mobile apps and games

Description

Developed by Facebook, React is a popular library for building impressive user interfaces. React extends its capabilities to mobile platforms using the React Native framework and integrates with popular web and mobile tools to build scalable applications. React Projects is your guide to learning React development by using modern development patterns and integrating React with powerful web tools, such as GraphQL, Expo, and React 360. You'll start building a real-world project right from the first chapter and get hands-on with developing scalable applications as you advance to building more complex projects. Throughout the book, you'll use the latest versions of React and React Native to explore features such as routing, Context, and Hooks on multiple platforms, which will help you build full-stack web and mobile applications efficiently. Finally, you'll get to grips with unit testing with Jest and end-to-end testing with Cypress to build test-driven apps. By the end of this React book, you'll have developed the skills necessary to start building scalable React apps across web and mobile platforms.

Who is this book for?

The book is for JavaScript developers who want to explore React tooling and frameworks for building cross-platform applications. Basic knowledge of web development, ECMAScript, and React will assist with understanding key concepts covered in this book.

What you will learn

  • Create a wide range of applications using various modern React tools and frameworks
  • Discover how React Hooks modernize state management for React apps
  • Develop web applications using styled and reusable React components
  • Build test-driven React applications using Jest, React Testing Library, and Cypress
  • Understand full-stack development using GraphQL, Apollo, and React
  • Perform server-side rendering using React and Next.js
  • Create animated games using React Native and Expo
  • Design gestures and animations for a cross-platform game using React Native
Estimated delivery fee Deliver to Poland

Premium delivery 7 - 10 business days

zł110.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Apr 29, 2022
Length: 384 pages
Edition : 2nd
Language : English
ISBN-13 : 9781801070638
Vendor :
Facebook
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Estimated delivery fee Deliver to Poland

Premium delivery 7 - 10 business days

zł110.95
(Includes tracking information)

Product Details

Publication date : Apr 29, 2022
Length: 384 pages
Edition : 2nd
Language : English
ISBN-13 : 9781801070638
Vendor :
Facebook
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just zł20 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just zł20 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 557.97
React Projects
zł157.99
React and React Native
zł201.99
Full-Stack Web Development with GraphQL and React
zł197.99
Total 557.97 Stars icon

Table of Contents

11 Chapters
Chapter 1: Creating a Single-Page Application in React Chevron down icon Chevron up icon
Chapter 2: Creating a Portfolio in React with Reusable Components and Routing Chevron down icon Chevron up icon
Chapter 3: Building a Dynamic Project Management Board Chevron down icon Chevron up icon
Chapter 4: Building a Server-Side-Rendered Community Feed Using Next.js Chevron down icon Chevron up icon
Chapter 5: Building a Personal Shopping List Application Using Context and Hooks Chevron down icon Chevron up icon
Chapter 6: Building an Application Exploring TDD Using the React Testing Library and Cypress Chevron down icon Chevron up icon
Chapter 7: Building a Full-Stack E-Commerce Application with Next.js and GraphQL Chevron down icon Chevron up icon
Chapter 8: Building an Animated Game Using React Native and Expo Chevron down icon Chevron up icon
Chapter 9: Building a Full-Stack Social Media Application with React Native and Expo Chevron down icon Chevron up icon
Chapter 10: Creating a Virtual Reality Application with React and Three.js Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Most Recent
Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.3
(10 Ratings)
5 star 30%
4 star 20%
3 star 20%
2 star 10%
1 star 20%
Filter icon Filter
Most Recent

Filter reviews by




Ann Dec 23, 2022
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
This book was intended to help me practice using React concepts with varying projects. Chapter 1 - old code casues webpack errors. Skipped to Chapt 2 because with create-react-app, one doesn't need webpack. Chapt 2, several errors caused me to look up the code in GitHub. The code in GitHub approaches the tasks differently. As a learner, this is frustrating.I would not waste my time or money on this book. It will only cause frustration.
Amazon Verified review Amazon
MzArlowe Sep 07, 2022
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
If you're a beginner, this book is just as good as anywhere else to start. Informative and insightful, it builds a great knowledge base. I would recommend, at least, ensuring that you're using the most up to date software as this books recommendations (like any other print) will be a bit out of date by this point. The only downside, are the projects will need a bit more vision than what this book can supply. Which, in turn, may need a bit more time to work through obstacles. I still would recommend this book.
Amazon Verified review Amazon
Robert Jul 19, 2022
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
The range of projects is what drew me to the book. I also like that the author explains how to setup webpack and babel from scratch in a fairly easy to understand way. I'm only partway through the book but so far my opinion has remained the same. From the first project you will run into a lot of code errors, in fact the very first project won't work if you follow the steps as they are laid out. It would take someone with experience with React, NPMJS and generally code debugging to get through the first project if not the whole book (although I haven't finished). Having said that, I do like the information so far. I may update this review later.
Amazon Verified review Amazon
Taylor Cerchie Jul 15, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Roy Derks's experience with coding in React and educating audiences comes through in his writing style. I'm enjoying learning how to create 3D objects with React and three.js with this book, and Roy sets the context well with high-level explanations of how the technologies interact. 10/10, would recommend.
Amazon Verified review Amazon
Britton A. Kitchell Jul 05, 2022
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
I’m halfway through this book and am really disappointed. I’ve learned a few tricks, but the actual projects would require a lot of revision/expansion to be functional. One of them (chapter 4) is broken/out of date if you install and run the code in their repo, and this book just came out. The rest look pretty bad and have bugs or broken/incomplete features.There are also lots of typos and oversights (e.g., loading state never gets set to true in at least two projects).Lastly, concepts are barely explained, which makes it that much harder to fix/improve the embarrassing projects. I just completed a Fullstack JavaScript bootcamp and have been able to salvage some things in here, but this would be a total waste of time if you are new to React.The “Full-Stack React, TypeScript, and Node” book by David Choi is much much better. I’d recommend that over this if you are a novice or intermediate and want to get a useful, thorough understanding that is transferable to future projects.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela