Many tutorials mention create-react-app
to 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 "big bang to life" procedure:
initialize the project with a
package.json
fileinstall a few dependencies (including
react
)create the foundational
public/index.html
filecreate our foundational
index.js
entry point filecreate our
App
filecreate other component files
Initializing the project
This applies not only to React projects but to any web project!
On a new folder, e.g. jonotype
, we will enter this following command on Terminal:
npm init -y
This creates a file named package.json
that describes our new web app:
// jonotype/package.json
{
"name": "jonotype",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
We can do a few modifications:
// jonotype/package.json
{
"name": "jonotype",
"version": "1.0.0",
"description": "",
/* here */
"main": "src/index.js",
"scripts": {
/* here */
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
/* here */
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"keywords": [],
"author": "",
"license": "ISC"
}
Updating the entry point
We update the main
property from index.js
to src/index.js
just to keep our files more organized!
Adding npm run
scripts
We then include our npm run
scripts - these enable us to run a local version of our app (webpage)!
Adding browserslist
The browserslist
property just excludes any ancient browsers like Internet Explorer!
Installing the dependencies
Now, we can install three dependencies (for now) which allow us to use the React library and family of scripts:
npm install react react-dom react-scripts
Upon installation our package.json
automatically updates to something like this:
// jonotype/package.json
{
"name": "jonotype",
"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",
/* this got updated */
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1"
}
}
(The dependencies
property adds in react
+ react-dom
+ react-scripts
!)
Creating the foundational HTML file
Once we let those dependencies install, we can create a new folder called public
, in which we can place our foundational index.html
file:
<!-- jonotype/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>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 datacharacter 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)<div id="root"></div>
the most important part here, where the React app lives!
Creating the foundational index.js file
Now, we will connect the foundational HTML file with a foundational JavaScript file; this src/index.js
file also happens to import the React scripts:
// jonotype/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 that errors will occur because we have not created the App
code yet, which will do in the next section!
Also note:
StrictMode
is a built-in component of React which outputs errors in the browser's console concerning any problems inside the<StrictMode></StrictMode>
tagcreateRoot
builds upon the DOM inindex.html
Creating the App.js file
Finally, let's get some real visible code going by starting a new file src/App.js
:
/* jonotype/src/App.js */
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 filesdefault
means that when weimport
this file elsewhere we do not have to call itApp
:
/* jonotype/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>
)
Creating other component files
Creating child components keeps our code more organized and "modular", so let's give this a try with src/Component.js
, with CamelCase
as the convention for component files:
/* jonotype/src/Component.js */
export function Component() {
return (
<div>
<p>A child component!</p>
</div>
);
}
Notice how we did not say export default function Component()
there!
Then, going back to src/App.js
we then import
and render Component.js
:
/* jonotype/src/App.js */
import { Component } from './Component.js'
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 functionComponent
fromsrc/App.js
We cannot replace
Component
with another name because we did not specify it as anexport default
back insrc/Component.js
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, then we could still give it an alias using the as
operator in the import
statement:
/* jonotype/src/App.js */
import { Component as Whatever } from './Component.js'
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 simply run the following command:
npm start
We should see something like:
Compiled successfully!
You can now view jonotype 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 something like:
Notice the relationship of components
"A child component!" lives in
src/Component.js
src/Component.js
gets imported bysrc/App.js
src/App.js
gets imported bysrc/index.js
src/index.js
builds uponpublic/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, insrc/App.js
- we could include
division of labour
- if we want to expand upon
src/Component.js
we could do so without affecting the rest ofsrc/App.js
- if we want to expand upon
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
deploying the app to the internet
creating dynamic components
building the illusion of a multi-page website through routes
Developers never get bored!
(By the way, you can see the final product in https://github.com/joncoded/jonotype)