React — creating apps from scratch

starting a React app without create-react-app
// updated 2025-05-15 11:58

So let's create a React app from scratch but let's make sure we have the following installed on our computer:

To check for node and npm, let's go on our Terminal app and enter the following when prompted (the $ sign will serve as a prompt in these examples, so do not type that in):

$ node -v
$ npm -v

If we see version numbers and have our code editor installed, let's begin!

So, many tutorials mention create-react-app to the beginners of React, which often includes redundancies and intimidating stuff on the side. However, another way exists! For a more bare-bones approach, we can follow this "end-to-end" (or "big-bang-to-life" procedure:

  • initialize the project
    • create a new package.json file
    • install a few dependencies (including the react library itself)
  • create the foundational files
    • public/index.html (for basic HTML structure)
    • index.js (for JavaScript)
    • App.jsx (for React) with JSX
  • create other component files
  • running the app

Initializing the project

The first subsection of this applies to any web project using npm, not just React projects, while the second subsection deals with importing the React library:

Creating package.json

Let's go back to our Terminal to run a command that creates a new folder, ourcraft, and opens it:

$ mkdir ourcraft && cd ourcraft

We will then ask npm to initialize our project:

$ npm init -y

This creates a file in the project root folder, i.e ourcraft/package.json that describes our new web app:

{
  "name": "ourcraft",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

We can modify that file in our code editor by improving:

  • the folder structure
    • by adding an src folder (for our app's root) to index.js
  • the developer experience
    • by adding script commands (to run a mock server)
    • by excluding obsolete browsers (for debugging)

So, ourcraft/package.json should now look like:

{
  "name": "ourcraft",
  "version": "1.0.0",
  "description": "",
  /* add src folder */
  "main": "src/index.js", 
  "scripts": { 
    /* add script commands */
    "start": "react-scripts start", 
    "build": "react-scripts build", 
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject" 
  },
  /* add browser list */
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "keywords": [],
  "author": "",
  "license": "ISC"
}

By adding the scripts properties, we can run commands like "npm run start" and "npm run build" to help us preview our work.

By adding the browserslist property, we can exclude support for any ancient browsers like Internet Explorer (or browsers that don't get used by more than 0.2% of the population!) More on this later...

Installing dependencies

Back in Terminal, we can install three dependencies that allow us to use the React library and its family of extensions:

$ npm install react react-dom react-scripts

Upon installation, ourcraft/package.json automatically updates to something like this:

{
  "name": "ourcraft",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "keywords": [],
  "author": "",
  "license": "ISC",
  /* npm install did this */
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "^5.0.1"
  }
}

Creating the foundational files

Once we let those dependencies install, we can create two new subfolders in ourcraft:

  • public where we place our foundational HTML file
  • src where we place our foundational JS file
    • as well as all our files relating to our app

The foundational HTML

In the public subfolder, we can create a file called index.html:

<!-- ourcraft/public/index.html -->

<!DOCTYPE html>
<html lang="en">

  <head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>ourcraft : our react app</title>

  </head>

  <body>

    <noscript>
      y u no use javascript? 
    </noscript>

    <div id="root"></div>

  </body>

</html>

Briefly, this minimal HTML file consists of:

  • the <head> tag for technical meta data
    • character set
    • browser sizing
    • <title> bar text
  • the <body> tag which has
    • <noscript> warning because React apps require JavaScript (which everyone should have enabled on their browsers)
    • the most important part lies in the <div> tag with an id of root, where the React app will live!

The foundational JavaScript

Now, in the src folder, we can create an index.js file:

// ourcraft/src/index.js

/* dependencies */
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import App from "./App"

/* manipulation of the index.html DOM */
const rootElement = document.getElementById("root")
const root = createRoot(rootElement)

/* displaying the React virtual DOM */
root.render(
  <StrictMode>
    <App />
  </StrictMode>
)

Note:

  • StrictMode is a built-in component of React which outputs errors in the browser's console (if errors exist)
  • createRoot is another built-in method that builds upon the DOM in index.html

Then, we will go back to the foundational HTML file and connect it with the foundational JavaScript file, right before the closing body tag:

<!-- ourcraft/public/index.html -->

<!DOCTYPE html>
<html lang="en">

  <head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>ourcraft : our react app</title>

  </head>

  <body>

    <noscript>
      y u no use javascript? 
    </noscript>

    <div id="root"></div>

    <script src="src/index.js"></script>
    
  </body>

</html>

The foundational React file

Finally, let's get some real visible code going by starting a new React file in the ourcraft/src folder:

/* ourcraft/src/App.jsx */

export default function App() {
  return (
    <div>
      <h1>Hello!</h1>
      <h2>Let's begin our React App!</h2>
    </div>
  );
}

Breaking that down:

  • export means we can use this file in other files
  • default means that when we import this file elsewhere we do not have to call it App but Whatever we want!

This next snippet is completely optional but illustrates the handiness of the default keyword:

/* ourcraft/src/index.js */

import { StrictMode } from "react"
import { createRoot } from "react-dom/client"

/* instead of */
// import App from "./App"

/* we can do this because we used "default" in App.js */
import Whatever from "./App"

const rootElement = document.getElementById("root")
const root = createRoot(rootElement)

root.render(
  <StrictMode>
    <Whatever />
  </StrictMode>
)

JSX

We may have also noticed an unusual syntax that looks like HTML tags. However, these tags behave a bit differently than HTML tags. We will have a closer look at these "JSX" (JavaScript XML) tags in a later JSX page.

For now, we will look at a call to a render function and tell ourselves that "this means render the HTML/XML inside the brackets".

Creating other component files

(Feel free to skip this section to "Running our app" to see just the bare-bones app!)

Creating child components keeps our code more organized and "modular", so let's give this a try:

/* ourcraft/src/Component.jsx */

export function Component() {
  return (
    <div>
      <p>A child component!</p>
    </div>
  )
}

Then, going back to src/App.jsx we then import and render Component.jsx:

/* ourcraft/src/App.jsx */

import { Component } from './Component'

export default function App() {
  return (
    <div>
      <h1>Hello!</h1>
      <h2>Let's begin our React App!</h2>
      <Component />
    </div>
  )
}

Some things to notice here:

  • We use curly braces for { Component } to extract the function Component from src/App.jsx
  • We cannot replace Component with another name because we did not specify it as an export default back in src/Component.jsx
  • Sometimes, specifying a default in a child component helps if we wish to rename the child component later on

Aliasing the imported component

If we want an imported component to have a different name, we could still give it an alias using the as operator in the import statement:

/* ourcraft/src/App.jsx */

import { Component as Whatever } from './Component'

export default function App() {
  return (
    <div>
      <h1>Hello!</h1>
      <h2>Let's begin our React App!</h2>
      <Whatever />
    </div>
  )
}

Oftentimes, we would need to do this if there exist naming conflicts!

Running our app

Finally, we can run our app! In Terminal, we would run the following command:

$ npm start

We should see something like:

Compiled successfully!

You can now view ourcraft in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.0.153:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

webpack compiled successfully

Then, from our browser, we go to localhost:3000 and we should see the page!

Notice the relationship of components:

  • The text "A child component" lives in src/Component.jsx
  • src/Component.jsx gets imported by src/App.jsx
  • src/App.jsx gets imported by src/index.js
  • src/index.js builds upon public/index.html

Clearly, the powerful implications of React components already appear in this very basic static "app" in terms of:

  • re-usability
    • we could include <Component /> as many times in as many places as we wish, in src/App.jsx
  • division of labour
    • if we want to expand upon src/Component.jsx we could do so without affecting the rest of src/App.jsx
  • portability
    • keeping things in smaller components makes code easier to read

Moving on

We have covered quite a bit here, starting from nothing and ending with a basic static app - but more exciting topics lie ahead! More, such as:

  • building the app
  • styling the app
  • deploying the app to the internet
  • creating dynamic components
  • building the illusion of a multi-page website through routes

Developers should never get bored!

⬅️ older (in textbook-react)
⚛️ React — an introduction
newer (in textbook-react) ➡️
React and JSX ⚛️
⬅️ older (in code)
⚛️ React — an introduction
newer (in code) ➡️
React and JSX ⚛️
⬅️ older (posts)
⚛️ React — an introduction
newer (posts) ➡️
React and JSX ⚛️