banner



How To Design Multi Page React App

Table of Contents

  • What is a SPA?
    • Controlling the DOM
    • Multi-page Behavior
      • How Do SPAs Get Data?
  • SPA vs. MPA
    • You Don't Have to Choose Between SPAs and MPAs
      • Gatsby.js
      • The Best of Both Worlds
  • How to Create a Multi-Page React App
    • Prerequisites
    • 1. Set-Up Application
      • Layout.js
    • 2. Add Router
      • Add CSS
      • Gatsby-Node
      • Default Route Components
    • 3. Create Nested Client-Side Routes
      • Data Parameters
    • 4. Sign Up For a Free Account on RapidAPI
    • 5. Subscribe to Finnhub API
    • 6. Fetch Stock Data from Finnhub
      • Add API-Key
      • Make API Call
  • Conclusion
      • Related Articles

What is a SPA?

Single Page Applications (SPAs) are applications that use one webpage for all their features. In the past, websites typically loaded new pages for each new request or link within the domain name.

For example, there would be an HTML page for:

  • /
  • /about
  • /contact
  • /blog
  • /blog/1

Individual HTML pages could be found at the respective URL on the server that accurately represented the file structure (i.e all blog posts were in the/blog folder). Therefore, when the browser needed the new page, it would request the new page from the server.

Navigating from/blog to/blog/1 would require a new HTML page.

View the Best Free APIs List

Controlling the DOM

The approach with SPAs is to turn many requests for HTML pages into one request for theindex.html page, CSS, and Javascript. Then, reactive Javascript frameworks take control of the document object model which is a tree-link structure representing the nodes on an HTML webpage.

For example, take a look at this HTML block:

<html>     <body>         <div>             <h1></h1>         </div>         <div>             <article></article>         </div>     </body> </html>

All of the elements inside an element are considered the children. Therefore,<body> is a child of <html>. Subsequently, <html> is the parent of <body>.

document object model

Javascript frameworks (React, Vue, etc.) control what is rendered to the DOM (in a much more complicated way) by controlling these elements of the tree. Instead of requesting a new tree, they manipulate the branches via the DOM.

Multi-page Behavior

If you have ever used create-react-app then you know there is only one HTML page in the public folder. Consequently, you might ask how can multiple URLs give the website a multi-page feeling? The answer: client-side routing libraries.

JavaScript libraries (most notably react-router-dom) allow the developer to register URLs—and their corresponding components—in one of the parent nodes of the DOM tree. Then, depending on the URL entered, certain nodes are rendered to the DOM, and others are not.

How Do SPAs Get Data?

SPAs that implement multi-page behavior still need to get data for the different components as components render. SPAs do not stop making HTTP requests after the initial request. They make smaller requests for only the data (typically JSON data) that is needed whereas a traditional website would request the entire HTML document again (as well as the data).

In React, the data fetching is done inside of the component with functions like componentDidMount or using React hooks.

SPA vs. MPA

There are certainly tradeoffs that happen when deciding whether to create a single page application or a multi-page application.

SPAs can be high performing applications once they have loaded in the client because they can route between components quickly. At the same rate, it could take longer to fetch the initial application due to the large Javascript code that is requested.

One of the biggest advantages/disadvantages cited when discussing SPAs vs. MPAs is search engine optimization.

Search engines have crawlers that index information found on websites. SPAs are dynamically rendered, so the information on the page is not always available when a crawler is trying to access it. If it does not render the HTML in time then the search engine will not be able to store the information. On the other hand, traditional websites have HTML pages that are static and can be crawled effectively when the crawler first finds the page.

You Don't Have to Choose Between SPAs and MPAs

Consider this example scenario. You have developed an app that utilizes rapidly changing data and you want the public to be able to find it. However, you are aware that if you create a SPA it could hurt the chances that people find your app with search engines.

Gatsby.js

Gatsby is a free and open source framework based on React that helps developers build blazing fastwebsites andapps

Gatsbyjs.org

Gatsby claims to be fast because the React code is transformed into static HTML pages. This can give an application the benefits of React as well as the benefits of having static assets for search engines to index.

Also, it's recommended for use on reactjs.org:

Gatsby is the best way to createstatic websites with React. It lets you use React components, but outputs pre-rendered HTML and CSS to guarantee the fastest load time.

You may be thinking that creating a static rendered site would defeat the purpose of our very fast dynamically rendered site and you are correct. However, Gatsby also supports client-side routing and client-side routing is what SPAs do.

The Best of Both Worlds

This means that using Gatsby, we can create static HTML pages for marketing purposes and have a dynamically rendered application for our product. That way we can be assured that the parts of the app that need to be indexed are static HTML and the parts of the app that are designed for fast user interaction are high-speed.

In this article, I hope to walk you through creating a multi-page React app with Gatsby that has static HTML pages combined with an application using client-side routing!

How to Create a Multi-Page React App

View the code on Github

Prerequisites

  • Node.js installed on your machine
  • Understanding of how to open a terminal, or command-line on your machine
    • Mac
    • Windows PowerShell
  • Internet connection
  • Basic Understanding of React components and React hooks
  • Code editor (I am using Visual Studio Code)

1. Set-Up Application

Open up a new terminal and run the following commands to get the project started:

$ mkdir rapidapi-multi-page-react-app $ cd rapidapi-multi-page-react-app/ $ npm init -y $ npm install --save gatsby react-dom react axios

The commands create a folder, initialize an NPM project, and install the packages we need.

Next, create some Gatsby specific folders and files.

  • src/pages/index.js
  • src/pages/app.js
  • src/pages/marketing.js
  • src/components/
  • gatsby-node.js

Thesrc,pages, andcomponents folders do not exist, so you will need to create them before adding the.js files.

Creating individual .js files in thepages directory is one of the ways to add static HTML pages to a Gatsby app. Consequently, the app has pages at/app,/ (index), and/marketing.

Layout.js

Layout.js is a common wrapper component in Gatsby that typically contains aspects of the page like the header, footer, and navigation.

Create the fileLayout.js incomponents and add the below code to it,

import React from 'react' import { Link } from 'gatsby'  const Layout = ({children}) => {     return (         <>             <nav>                 <Link to='/'>Home</Link>                 <Link to='/app'>App</Link>                 <Link to='/marketing'>Marketing</Link>             </nav>             <main>                 {children}             </main>         </>     ) }  export default Layout

<Link> is a Gatsby component, that uses @reach/router, to quickly navigate between views in Gatsby.

Now that we have a layout component we can add components to the static HTML pages.

Inindex.js add the code,

import React from 'react'; import Layout from '../components/Layout'  const Home = ({location}) => {   return (     <Layout>       <h1>Home Page <span>{location.pathname}</span></h1>       <h2>Static HTML Page</h2>     </Layout>   ) }  export default Home;        

Inside ofmarketing.js add,

import React from 'react'; import Layout from '../components/Layout'  const Marketing = ({location}) => {   return (     <Layout>       <h1>Marketing Page <span>{location.pathname}</span></h1>       <h2>Static HTML Page</h2>       <p>Aiming for better SEO</p>     </Layout>   ) }  export default Marketing;

And finally, add the below code toapp.js,

import React from 'react' import Layout from '../components/Layout' const App = ({location}) => {     return (         <Layout>             <h1>Welcome to the App Page <span>{location.pathname}</span></h1>         </Layout>     ) }  export default App;        

In the terminal, execute the command npm install -g gatsby-cli . This installs Gatsby's CLI globally.

After it installs, rungatsby develop in the project's root folder to start the development server.

This command takes a little bit of time to get warmed up, however, once it's complete navigate to http://localhost:8000 to view the application.

gatsby develop

2. Add Router

index.js andmarketing.js are complete. When Gatsby builds, the components will be transformed into static HTML pages that load quickly and have better SEO.

However,app.js is going to hold our dynamically routed application.

First, importRouter andLink from @reach/router underneath where we import React at the top of the page.

import { Router, Link } from "@reach/router"

The<Router> component accepts child components that are mapped to specific URLs within the router.

Let's add a basic information route to demonstrate this.

Add the fileMyInfo.js in thecomponents folder with the code,

import React from 'react'  const MyInfo = (props) => {     return (         <>             <h2>My Info View</h2>             <h3>Client-Only Route</h3>             <table>                 <tr>                     <th>                         Name                     </th>                     <td>                         your name                     </td>                 </tr>                 <tr>                     <th>                         Email                     </th>                     <td>                         example@demo.com                     </td>                 </tr>             </table>         </>     ) }  export default MyInfo

Next, inapp.js, add the router and a link to the new page. Below theh1 tag, but still inside of the Layout component, add:

<nav>     <Link to='/app/info'>Info</Link> </nav> <Router basepath="/app">     <MyInfo path="/info" /> </Router>

Notice that the<Router> component takes abasepath property. This can help clean up the child routes and, in our case, defines the page to find the client-only routes.

ImportMyInfo.js at the top ofapp.js.

import MyInfo from '../components/MyInfo'

Add CSS

Before navigating around our new app, add some CSS to make it a little easier to look at.

In components add the filelayout.css and insert the styles below,

a {     display: block;     text-decoration: none;     padding: 0.25rem .6rem;     color: white; }  nav {     background: #534B52;     list-style-type: none; }  td {     padding: 5px 10px;     text-align: center; }  th {     padding: 5px 10px;     color: white;     background-color: black; }  table {     border-spacing: 5px; }  h1 {     color: #2C302E; }  h2 {     color: #474A48; }  h3, h4 {     color: #909590; }  h1,h2,h3,h4 {     border-bottom: 2px solid #9AE19D; }  span {     background: #9AE19D;     padding: 1px;     margin: 3px;     border: 1px solid black; }

Next, import the file at the top ofLayout.js.

import './layout.css

These styles are global and will be applied to all components.

Gatsby-Node

gatsby-node.js can be an important file in any Gatsby app. Furthermore, it's another place where pages can be created.

If you tried to navigate to the Info page on the app it would not be found. We need to add 'page-holders' to the Gatsby app so thatLink components can find the right views. This is a little quirk with Gatsby, but if this wasn't done hyperlinks to views would not work.

Ingatsby-node.js add,

// This is called after every page is created. exports.onCreatePage = async ({ page, actions }) => {     const { createPage } = actions      if (page.path.match(/^\/app/)) {         // page.matchPath is a special key that's used for matching pages         // with corresponding routes only on the client.         page.matchPath = "/app/*"          createPage(page)     } }

You can read more about the uses ofgatsby-node.js here.

Restart the Gatsby application in the terminal for the page to work properly. Finally, visit the info page when the app restarts. You should see the new client-only route we created.

my info component

Great work! You have added your first client-side route!

Default Route Components

Notice that no component is rendered when we first navigate to /app. Let's change that by adding a default component as a child of<Router>.

Incomponents, create the fileDefault.js and add the code below,

import React from 'react'  const Default = (props) => {     return (         <>             <h2>Default App View</h2>             <h3>Client-Only Route</h3>         </>     ) }  export default Default

Next, import the component at the top ofapp.js and add it inside of the<Router> component.

Now, when we visitapp.js there is a component that renders as the default. However, we can still navigate to the info component if needed.

3. Create Nested Client-Side Routes

Despite our work so far, the client-side routes are lacking the dynamic functionality that we are looking for. Thankfully, <Router> child components can have children of their own. These are nested routes.

Let's create a dashboard component at /app/dashboard that has a default child component.

First, create the fileDashboard.js incomponents and add the code,

import React from 'react' import { Link } from 'gatsby'  const DataDashboard = ({children,uri}) => {     return (         <div>             <h2>Data Dashboard</h2>             <h3>Client-Only Route</h3>             <nav>                 <Link to={`${uri}/tsla`}>Data for Tesla</Link>                 <Link to={`${uri}/aapl`}>Data for Apple</Link>             </nav>              {children}         </div>     ) }  export default DataDashboard

The two routes that we link to do not exist yet, but notice that they use theuri prop that is passed to components that add a little DRY programming to the links. In our case, the property has a value of/app/dashboard.

Next, add theDashboardDefault.js component to the same folder and insert the code,

import React from 'react'  const DashboardDefault = () => {     return (         <div>             <h2>Nested Dashboard Index</h2>             <p>This gets rendered when no data parameters are provided.</p>         </div>     ) }  export default DashboardDefault

Then, import these components at the top ofapp.js

... import DashboardDefault from '../components/DashboardDefault' import Dashboard from '../components/DataDashboard' ...

Below the <MyInfo /> route add the new route with the nested default and create a link for it in the nav tag. Here's a look at the code the component now contains;

import React from 'react' import Layout from '../components/Layout' import { Router, Link } from "@reach/router" import MyInfo from '../components/MyInfo' import Default from '../components/Default' import Dashboard from '../components/Dashboard' import DashboardDefault from '../components/DashboardDefault'  const App = ({location}) => {     return (         <Layout>             <h1>Welcome to the App Page <span>{location.pathname}</span></h1>             <nav>                 <Link to='/app/info'>Info</Link>                 <Link to='/app/dashboard'>Dashboard</Link>             </nav>             <Router basepath="/app">                 <Default path="/" />                 <MyInfo path="/info" />                 <Dashboard path="/dashboard">                     <DashboardDefault path="/" />                 </Dashboard>             </Router>         </Layout>     ) }  export default App;        

After adding the code above and navigating to the dashboard page, you should see the default dashboard component rendered.

dashboard default component

Data Parameters

We can pass data parameters down into the child components of the dashboard in two steps.

  1. Create child component
  2. Define the data parameter in the path property

First, create the fileData.js incomponents and add the following component to it:

import React from 'react'  const Data = ({ dataId }) => {     return (         <>             <h2>Data View for {dataId.toUpperCase()}</h2>             <h3>Nested Client-Only Route</h3>         </>     ) }  export default Data

Notice, we are expecting a property nameddataId to be available to the component.

Next, import the component intoapp.js and add the component with thedataId parameter specified in the path.

....                 <Dashboard path="/dashboard">                     <DashboardDefault path="/" />                     <Data path=":dataId" />                 </Dashboard> ....

Parameters can be extracted from URLs by placing a colon in front of the parameter.

Now when you click on the links 'Data for Tesla' and 'Data for Apple' the dataId parameter is available in the Link component and passed down to the child.

Furthermore, we are showing how to access that property from the child component by extracting it from the props and displaying the ticker symbol in the header.

Clicking between the links, you notice that the URL parameter is changing along with the property.

Well done! URLs can now pass on dynamic data to nested child components. The final task will be doing something useful with the parameter.

However, we are going to fetch the data using RapidAPI.

4. Sign Up For a Free Account on RapidAPI

You will need an account on RapidAPI before subscribing to The Finnhub API. Visit RapidAPI to get signed up if you haven't already!

sign up for an account on rapidapi

5. Subscribe to Finnhub API

If you haven't guessed, we are going to be fetching stock data, and this can be done with the Finnhub API.

Search for Finnhub API or follow this link to the subscription page. Select the basic subscription.

finnhub pricing

Notice I have already subscribed to the Basic plan. Therefore, I have a link to Manage and View Usage that takes me to the developer dashboard.

You can track your API usage on the dashboard in case you have concerns about approaching your quota for any of the APIs that you subscribe to.

We have a rate limit of 60 requests per minute, which is plenty.

6. Fetch Stock Data from Finnhub

Using React hooks, let's fetch stock data and display it in theData component.

Add API-Key

WARNING:This method does not secure your API key in production. It is only used to simulate data fetching in an application and hide the API key for public repositories.

Create the files.env.development and.gitignore in the root of the project.

In.gitignore, add the code,

.cache node_modules public .env.* .env

and inside of.env.development add,

RAPIDAPI_KEY=yourapikey

You can find your API key on the Finnhub dashboard located in the middle section.

rapidapi key

Restart the Gatsby application once you have added your key to.env.development

Make API Call

Replace the previous code inData.js with the code below:

import React from 'react' import axios from 'axios'  const Data = ({ dataId }) => {     let [quote, setQuote] = React.useState('')      React.useEffect(() => {         axios({             "method": "GET",             "url": "https://finnhub-realtime-stock-price.p.rapidapi.com/quote",             "headers": {                 "content-type": "application/octet-stream",                 "x-rapidapi-host": "finnhub-realtime-stock-price.p.rapidapi.com",                 "x-rapidapi-key": process.env.RAPIDAPI_KEY             }, "params": {                 "symbol": dataId.toUpperCase()             }         })             .then((response) => {                 setQuote(response.data)             })             .catch((error) => {                 console.log(error)             })     }, [dataId])     return (         <>             <h2>Data View for {dataId.toUpperCase()}</h2>             <h3>Nested Client-Only Route</h3>             {quote && <div>                 <table>                     <caption>Quote as of {new Date(Number(quote.t)*1000).toDateString()} for {dataId.toUpperCase()}</caption>                     <tr>                         <th>Current</th>                         <th>High</th>                         <th>Low</th>                         <th>Open</th>                         <th>Previous Close</th>                         <th>Time</th>                     </tr>                     <tr>                         <td>{quote.c}</td>                         <td>{quote.h}</td>                         <td>{quote.l}</td>                         <td>{quote.o}</td>                         <td>{quote.pc}</td>                         <td>{new Date(Number(quote.t)*1000).toLocaleTimeString()}</td>                     </tr>                 </table>             </div>}         </>     ) }  export default Data

It can look like a lot of code, but not there are not that many things happening in the component.

When the component loads, the API call in React.useEffect is fired off with thedataId parameter that it received from its parent.

Then, the response data is set to the state variablequote.

Finally, when the state variable has data, the data is extracted and rendered to the component.

final app displaying stock data for apple

Notice that switching back-and-forth between the links does not reload the page even though the URL changes. However, new data is fetched from the API! Even with a simple application, you can see the performance benefits.

We can further test our dynamic routes by manually changing the URL.

Change your URL in the browser to http://localhost:8000/app/dashboard/ba

Although this link is not an option in the dashboard, the component receives the new data parameter and fetches the current stock data for Boeing (BA).

dynamic route fetched for boeing stock

Congratulations on creating this multi-page React application!

Conclusion

In this article, we discussed SPAs and MPAs and the tradeoffs between the two approaches. Furthermore, we saw that you don't need to pick between the two if you chose to use a technology like Gatsby.js to build your application.

Enhanced SEO combined with fast dynamic page routing can be a beneficial set-up for many types of web applications.

I hope you enjoyed creating the application and that what you learned fits into your future applications!

If you have questions about the article or application please leave a comment below!

Related Articles

  • How To Create a React App Using Typescript
  • How to Fetch Data from an API with React Hooks
  • How to fetch data with GraphQL and React

View the Best Free APIs List

How To Design Multi Page React App

Source: https://rapidapi.com/blog/react-multi-page-app/

Posted by: conklinlosetto.blogspot.com

0 Response to "How To Design Multi Page React App"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel