1. What You will Learn
As you work through this developer guide, you will learn:
- How to install NodeJS and ReactJS on your computer
- How to properly organize your React app's codebase
- How to create React components to hold the UI for your frontend app
- How to create basic routes for your app's components
- How to apply styling to your React components
- About best practices for learning and developing React apps (and apps in general)
- ... and a few tips and notes here and there about developing web apps using the React library.
Let's get started ...
2. Install NodeJS and ReactJS
Before we can start building our React app, we need to install a few things:
- NodeJS: This is the V8 engine that runs JavaScript and JavaScript-based programs and packages such as NodeJS, ExpressJS and ReactJS. See the official installation guide for instructions on how to install NodeJS on your computer
- ReactJS: This is the frontend library/framework that we commonly call "React". It contains features and tools to enable us build frontend apps using JavaScript, HTML and CSS. See the [React installation guide for how to properly install React on your system.
Once you have confirmed that you have properly installed both NodeJS and React on your system, it's time to start developing the app.
But, first, a few "house-keeping" things to take care of.
3. What we are Going to Build
So, what sort of app are we going to build here?
Great question (if you asked :) )
Throughout this guide, we are going to walk through how to build a simple "personal" app. This app will:
- Contain a home page, an "about me" page and a "contact me" page.
- Use simple CSS styling to give some of the UI components of the app a better "look and feel", but nothing overly complex.
- Implement simple state management within the app's components.
- Do some routing for the components (so that our users can navigate through the "pages" of the app.)
As we work through building the app, we will cover each of these above-mentioned parts in more detail.
With that said, let's start the work of building our "billion dollar" app. :)
4. Create the React App
There are two popular ways to start a React app:
- Using CRA: `Create-React-App` was the original/default way of starting a React app.
When you run the `create-react-app` command from your command line, all the necessary packages and libraries are installed into the React app's root folder, and the sub-folders (`public/`, `src/`) and files (`package.json`, `README`, etc.) are generated.
See the official CRA documentation for details on how to start a React app using the CRA command line tool.
- Using Vite: This is a more recent tool that you can use to start frontend apps for the VueJS, ReactJS, etc. frameworks.
When you run the `vite` command, a React app's folder is created, the initial packages and libraries are installed and the initial folders of the React app are created. See the Vite documentation for how to start a React app using Vite.
In this guide, we are going to use CRA to start our React app.
So, first, install the `create-react-app` tool from your command using:
npm install create-react-app
Next, open your terminal and run:
create-react-app personal
This will create a new `personal` folder in your current directory. This `personal` folder will contain the foundation folders and files that your React app will be built upon. Some initial NPM package will also be installed. (Check the `package-lock.json` file and `node_modules/` folder for a list of the currently-installed NPM packages .)
You should take some time to look at the generated files and folders (and their contents). Almost all of your work when building a React app will be done inside the `src/` folder of the app.
So, `cd` into the `src/` folder and let's create some sub-folders to hold the files and code for our React app.
5. Create React App's Structure
We should create the folder structure of our React app to reflect the various parts of a React app.
Almost all of our app development will go inside the `src/` folder of the generated app.
So, what goes into building a React app? What are the various things you need to do when building a React app?
Let's touch on that before we move forward...
A React app consists of:
- Components: These are the pieces of the app's UI. They are essentially the "pages" of the app.
But a component doesn't have to mimic a full "page".
It could be a simple unit of the page, such as a form, the footer or header of the app.
We will create a few components as we work through this guide. So, hang in there even if just for a while.
- Styling: These can be the custom CSS stylesheets you created or CSS classes from a CSS framework.
It also can be "raw" CSS you write inline (i.e. inside the HTML/JSX markup of your React components). We will be doing some bare-bones styling in this guide.
- API Calls: If your React app is even barely more than "child's play", it will be making CRUD requests over HTTP to a backend API server to get, update, delete and create new data for/from the app's components.
There are a number of tools to help you make and manage these API calls, including the Fetch API and axios-http. We won't be covering either in this guide.
- Routes: This is how you determine and manage navigating between the components of the app. These can simple or complex. We will be doing some routing in this guide.
- State Management: This is how you manage the state (i.e data) of your app's components. React has built-in state management solutions and also supports third-party state managers.
We will be covering simple local component state management in this guide.
- Testing: No serious app (whether backend or frontend) is complete without thorough automated tests. There are a number of testing libraries (and approaches) for writing automated tests for your React apps.
We won't be covering testing in this guide.
Ideally, we will create a folder (or a set of them) for each aspect of our React app.
So, we will create a folder each for the components, API calls, tests, CSS stylesheets, state management logic, and so on.
So, let's be modular and do that:
6. Create the App Folders
Let's a folder to hold our app's components. We will call this folder "components" so that there is no ambiguity.
Change into the `src/` directory of your React app's root folder.
cd personal/src/
Next, create the "components" folder inside the `personal/src/` directory.
mkdir components
We will come back to this folder later when we start to build our app's components.
If were going to make API calls we would have also created a `src/apis/` folder. We can also create a `src/css/` folder to hold any custom CSS stylesheets we had for our app.
But we won't be needing either custom stylesheets or API calls for such a simple app. So, we will skip over creating those folders.
By the way, you can name your folders anything as long as their names make sense to your fellow developers and aren't ambiguous. So, `src/api` is just as good as `src/apis`. And, `src/styles/` is just as valid as `src/css`. But it is better to be simple and explicit in your app's naming conventions than trying to be creative with it.
You can use your creative boost and smarts when building the app's components, routes, state management logic, styles and others. But keep the app's folders' and files' names simple and easily recognizable.
7. Create the App Components
Next, change into the `src/components/` folder and let's start building our components.
So, `cd src/components/`.
But, before we starting creating files and writing code (and all that jazz), let's know what we are doing and why before the "how" of it?
So, what is a component?
A component (in the frontend sense) is a piece of your app's UI. It could be a whole page or a form, the header, the footer, the side bar or even a single `div` element.
A component will contain one or more HTML/JSX tags. It could be styled or not. It could a simple button, a blurb of text, an interactive map or a complex work of UI awesomeness. It is still a component.
In our `personal` app, we will create the following components:
- PersonalHome: This will be the default "page"/UI that a user sees when he/she visits the root URL of your web app.
- AboutMe: This component will contain some biographical details about you.
- ContactMe: This component will contain a form that a user can fill in to send you a message.
So, let's start developing each of these components (inside the `src/components/` folder of your React app.)
Every component will contain a file of the same name as the component. The file's extension should be ".js" since it is a JavaScript file even though you will be writing some HTML (or "JSX" to be accurate) in the file.
So, change into the `src/components/` folder (if you are not already in there) and let's build some React components.
7.1: Create the Home Component
1. Create the component file.
touch PersonalHome.js
Now, open that component file in your favorite code editor (Visual Studio Code, Atom, Sublime Text, etc.)
NOTE: We could have named the component `Home`, `MyHome`, `AppHome`, and so on. But we went with `PersonalHome`. The name doesn't make a difference (as long as it doesn't start with a lowercase letter; aha, gotcha!): your users won't discover your awkward component-naming schemes. Just code the component correctly and you will be good to go.
Once you open the `PersonalHome.js` file in your code editor, let's start building it.
Add these lines of code to the file:
import React from 'react'
const PersonalHome = () => {
return (
<div>
<h3> Welcome to My Personal Site Online</h3>
<p>
"The Personal" is the web app where I live online.
It is my virtual home away from my brick-and-mortar home.
</p>
<p>
So, welcome!
</p>
</div>
)
}
export default PersonalHome
Now, let's import the `src/components/PersonalHome` component file (minus the file extension) into the root `App` component (which you will find inside the `personal/src/App.js` file.)
So, let's open up the `src/App.js` file and:
- import our custom `PersonalHome` component into it.
- Register the `PersonalHome` component inside `return()` statement of the root `App` component.
// src/App.js
import './App.css';
// Any additional imports go here too
// Other imports removed for brevity
import PersonalHome from './component/PersonalHome';
function App() {
return(
<PersonalHome />
)
}
export default App;
NOTE: I cleaned out almost all of the boilerplate code you would have found when you first opened the `src/App.js` file. So, do the same thing.
Now, start your React dev server (with `npm run start`) and visit "http://localhost:3000" in your browser. You should see the contents of your `PersonalHome` component rendered as-is.
Congratulations! You just created and rendered a React app component!
So, how does a React component get rendered when you visit the app in the browser?
7.2: How Components are Rendered in React
So, after building your app's component, how do you make it appear when you visit the app in the browser? How does the component get rendered?
There are three (3) ways to render a component within your React app:
- Add it to the Root `App` Component: When you first start your React dev server (with `npm run start` or `yarn run dev`), you will see the contents of the root `App` component (which is in the `src/App.js` file) rendered in the browser.
So, it follows that if you add anything (another component, HTML/JSX tag, text, etc.) into the `App.js` file, then it should be rendered as well when you visit the app in the browser. We will demonstrate this shortly.
- Add it to Another Rendered Component: So, for example, if an app's `PostDetail` component is already rendered, then if we add a `CommentDetail` component inside the (already rendered) `PostDetail` component, then the `CommentDetail` component will also now be (automatically) rendered when you view the app in the browser.
We will also use this approach in some of our `personal` app's components as we work through this guide.
- Create a Route for the Component: If you configure routing for your React app, then any component that has a route created for it will also be rendered when the component's route/URL path is visited in the browser.
We will do some basic routing in our `personal` app in this guide too.
Now, that we know how to create and render a component, let's touch on one other very important issue: "what goes into building a React component?"
7.3: What Goes into Creating a React Component
There are a few things that are involved when we say we are creating a React app. These include:
- The Markup: At the end of the day, what gets rendered for your viewers is the HTML markup that make up your component.
Those headers, divs, paragraphs, lists and links are all HTML tags/elements. Except in React, your HTML is smarter and is actually an extension of JavaScript. And, the markup is not simply HTML; it is JSX.
- Styling: To give your component a better "look and feel" and make it appealing to your users, you have to use CSS to style the JSX tags/elements. This can be done using inline styling, JavaScript style objects or external stylesheets.
See our Simple and Dynamic Styling in React guide for details of how to style your React components.
- API Calls: If your component is anything more than a trivial blurb of static text, you will need to make API calls to a backend server to GET, POST, UPDATE and DELETE data used in your React components.
Many tools/libraries exist to help you do this.
See my Learn How to Use the `axios-http` Library in your React App to Make API Calls over HTTP to your Backend Server guide for details.
- State Management: Each component will have some data attached to it.
This could be the title and body of your `BlogPost` component or the form fields in your `Registration` component, the product price and description in your `ProductDetail` component, the name and profile picture in your `UserProfile` component, etc.
These pieces of data in your components are what we call "state" in React lingo.
If your component's state is simple, then you can use built-in hooks like `useState()`, `createContext()` and `useContext()` to manage it.
If your React app's component state is more complex, then you can use a more complex state management solution like the Context API or the Redux Toolkit to manage that complex state across different components of your React app.
In our example `personal` app's components in this guide, we will be using the `useState()` hook to manage a component's local state.
- Event Handling: If you build your app to be used by users (duh, I know), then your users will be clicking around, dragging things, filling in form fields and a host of other interactions with your apps.
All these actions trigger what we call "events" in the web development world.
So, as a serious frontend developer, you need to be able to learn how to handle events in your React components.
I wrote a great guide (if I say so myself), to be published in a few days, titled "The Frontend Developer's Guide (and Cheatsheet) to Web Events, Event Listeners and Event Handling in React" that you should check out if you want to be sufficiently-knowledgeable on how to handle events in your React components.
Depending on the nature, scope and complexity of your React app, you may need to do other things (perform calculations, track device orientation, draw on the UI, load sounds in the background, etc.) in your React components. But the above-mentioned 5 things are usually the most common aspects of developing a React component.
Now that we know what goes into developing a React component, let's develop some components for our uber-cool `personal` app.
7.4: Create the 'About Me' Component
Next, let's create build the `About Me` component. This component, as you may have guessed, will contain some biographical info about you.
So, head on over to the `src/components/` folder of your `personal` app in your terminal and create the component file, with:
cd src/components
touch AboutMe.js
Now, open the `AboutMe.js` file in your code editor and start building it.
Your `src/components/AboutMe.js` component file should now look like this (unless you make it prettier):
import React, {useState} from 'react'
const AboutMe = () => {
const [firstName, setFirstName] = useState("Muhammad")
const [jobTitle, setJobTitle] = useState("Frontend Developer")
const [cityName, setCityName] = useState("New York")
const [hobbies, setHobbies] = useState([
"Coding", "Poetry", "Running", "Writing", "Traveling"
])
const [website, setWebsite] = useState("https://Jalloh.com/")
return (
<div>
<h3> About Me </h3>
<p>
My name is {firstName}. I am a {jobTitle} from {cityName}.
</p>
<p>
I have a few hobbies including:
</p>
<ul>
{hobbies.map(hobby => (
<li> {hobby} </li>
))}
</ul>
<p>
I am also a poet. You can read my elegies, eulogies and romantic verses on {website}.
</p>
</div>
)
}
export default AboutMe
With this component, we went a step further and:
- Used the built-in React `useState()` hook to help initialize (and, later, if needed, set the new values of) the component's pieces of state.
- Initialized various types of state: A React component's state can be of any valid JavaScript data type. So, it can be a string, number, boolean, array or object. Try creating a `userInfo` state (with `firstName`, `lastName` and `yearOfBirth` keys and values) and try rendering that inside the `return()` statement of your component.
- Implemented conditional rendering: There a few ways to do conditional rendering in your React components.
The `condition && (<> render this </>)` format is what we used here to conditionally render a paragraph only if there is a valid value for the component's `website` state.
Make the "website" state empty (i.e. "") and see how that affects how your component renders.
For other ways of implementing conditional rendering in your React components, please, see (soon-to-be-published) JSX: The Cheatsheet for the Frontend/React Developer guide.
Worth Noting: When creating a component, DON'T give it a camelCased name (like `aboutMe`, `blogPost`, etc.) Instead, make sure the component starts with a capital letter and contains no spaces (like `AboutMe` √, `BlogPost` √, etc.)
If you insist and want to see what errors you get if you camelCase your component's name, go ahead and do it and see what errors React spews out at you in your terminal console and in your browser.
7.5: Create the 'Contact Me' Component
Next, let's create our final component: the `Contact Me` component.
This component, which we will simply name `ContactMe`, will have a form that user fills in to send you a message.
So, create a new `src/components/ContactMe.js` file, open the file in your code editor and let's get coding.
Your `ContactMe` component should, after a couple of minutes of coding, look something like this:
import React, {useState} from 'react'
const ContactMe = () => {
const [name, setName] = useState('')
const [senderEmail, setSenderEmail] = useState('')
const [messageTitle, setMessageTitle] = useState('')
const [message, setMessage] = useState('')
return (
<div>
<h2> Leave me a Message </h2>
<form style={{ margin: '25px', padding: '30px'}}>
<input
type="email"
value={senderEmail}
onChange={(e) => setSenderEmail(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<input
type="text"
value={messageTitle}
onChange={(e) => setMessageTitle(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter your message here."
style={{ width: '100px', marginBottom: '15px'}}
/>
<button type="submit" style={{ margin: '10px auto'}}> Send Message </button>
</form>
</div>
)
}
export default ContactMe
In this "version 1.0" of the `ContactMe` component, we:
- used the built-in React `useState()` hook to initialize and set the value of the component's various pieces of state (`name`, `senderEmail`, etc.)
- used the `value` attrribute to tie a piece of the component's state (e.g. `senderEmail`) to input from an element on a form (such as the <input > element of type "email".)
- made use of the `onChange` event listener to listen/watch out for any user input in the form so that we can update/set the associated component state (such as setting the value of the component's `message` to what the user entered into form's `<textarea />` element.)
- used some basic inline styling to give our form and its sub-elements a better look and feel than would have been the default.
For a more detailed guide on the various ways of styling your React components, please, see my How to Implement Simple and Dynamic Styling in your React App guide.
For now, a user can enter data into the form's fields and that data would become the new value of component's local state. But we haven't implemented how to handle the data the user entered into the form once he/she hits "submit".
So, let me show you how to handle form input.
To do that, we will:
- create a new function (within the component itself) where we will implement the logic for what to do with the form data (that's also now the new state of the component).
We can call this function anything (sensible); we will go with `sendMessage()` to keep it simple and sensible. The `sendMessage()` function is what is called an "event handler" because it handles an event (in this the "submit" event on the form).
- add an `onSubmit` event listener to the `<form>` tag itself to "listen for" when a user hits the "submit" button on the form.
- pass the `sendMessage` event handler (without the braces `()` so that the function doesn't get executed immediately when the component renders) to the `onSubmit` event listener.
This way, once a user hits the "submitt" button, the contents of the `sendMessage()` event handler will be executed.
So, let's finish up this component by implementing the above things.
Update the `ContactMe` component to look like this:
import React, {useState} from 'react'
const ContactMe = () => {
const [name, setName] = useState('')
const [senderEmail, setSenderEmail] = useState('')
const [messageTitle, setMessageTitle] = useState('')
const [message, setMessage] = useState('')
const [formError, setFormError] = useState('')
function sendMessage(e){
e.preventDefault()
// So that the form doesn't get submitted to the current URL path,
// which is the "default" behavior when a "submit" button on a form is clicked
if(name && senderEmail && messageTitle && message){
// Only process the form's input data if all the form fields were filled in correctly
const contactMessage = {
name: name,
senderEmail: senderEmail,
messageTitle: messageTitle,
message: message
}
const messageJson = JSON.stringify(contactMessage)
// Now, you can decide what to do with the JSONified message: messageJson
// Usually, this would involve calling a backend API to send the message
// to yourself or a chosen team member.
// But we don't have an external API to call to do that.
// So, we will settle for just console logging it
console.log(`${name} from ${senderEmail} sent you this message: ${message}`)
}else {
// If the form wasn't correctly or fully filled in, render an error for the user.
setFormError("Please, fully and correctly fill in all the form fields.")
}
}
return (
<div>
<h2> Leave me a Message </h2>
{formError && (
<> {formError} </>
)}
<form onSubmit={sendMessage} style={{ marginTop: '25px', padding: '30px'}}>
<input
type="email"
value={senderEmail}
onChange={(e) => setSenderEmail(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<input
type="text"
value={messageTitle}
onChange={(e) => setMessageTitle(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter your message here."
style={{ width: '100px', marginBottom: '15px'}}
/>
<button type="submit" style={{ margin: '10px auto'}}> Send Message </button>
</form>
</div>
)
}
export default ContactMe
With "version 2.0" of the `ContactMe` component, we:
- implemented the `sendMessage()` event listener (function's) logic.
- added a new piece of the component's state - `formError`- so that we can render an error message if some of the form's fields were not fully or correctly filled in.
There is just one issue: there is no way of re-rendering the component should be value of the `formError` state change (as would happen if a user hits the "submit" button on the form before fully and correctly filling in all the form fields). We handled setting the message for the `formError` state inside the `else` block within the `sendMessage()` event handler.
But how does the component know that the `formError` state's value has changed? And, equally importantly, how does the component re-render after any of its pieces of state (like `formError`, in this case) changes?
That's where the
useEffect hook comes in. You can read more about it on that page. But, for now, let's just see how to simply use the `useEffect()` in our component.
Update the `ContactMe` component to look like this:
import React, {useState, useEffect} from 'react'
const ContactMe = () => {
const [name, setName] = useState('')
const [senderEmail, setSenderEmail] = useState('')
const [messageTitle, setMessageTitle] = useState('')
const [message, setMessage] = useState('')
const [formError, setFormError] = useState('')
function sendMessage(e){
e.preventDefault()
// So that the form doesn't get submitted to the current URL path,
// which is the "default" behavior when a "submit" button on a form is clicked
if(name && senderEmail && messageTitle && message){
// Only process the form's input data if all the form fields were filled in correctly
const contactMessage = {
name: name,
senderEmail: senderEmail,
messageTitle: messageTitle,
message: message
}
const messageJson = JSON.stringify(contactMessage)
// Now, you can decide what to do with the JSONified message: messageJson
// Usually, this would involve calling a backend API to send the message
// to yourself or a chosen team member.
// But we don't have an external API to call to do that. So, we will settle for just console logging it
console.log(`${name} from ${senderEmail} sent you this message: ${message}`)
}else {
// If the form wasn't correctly or fully filled in, render an error for the user.
setFormError("Please, fully and correctly fill in all the form fields.")
}
}
useEffect(() => {
}, [formError])
return (
<div>
<h2> Leave me a Message </h2>
{formError && (
<> {formError} </>
)}
<form onSubmit={sendMessage} style={{ marginTop: '25px', padding: '30px'}}>
<input
type="email"
value={senderEmail}
onChange={(e) => setSenderEmail(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<input
type="text"
value={messageTitle}
onChange={(e) => setMessageTitle(e.target.value)}
style={{ width: '100px', marginBottom: '15px'}}
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Enter your message here."
style={{ width: '100px', marginBottom: '15px'}}
/>
<button type="submit" style={{ margin: '10px auto'}}> Send Message </button>
</form>
</div>
)
}
export default ContactMe
And, that's a wrap on the UI and logic of our `ContactMe` component.
Now, we just need to figure out how to render the `ContactMe` component when we load our app in the browser.
8. Create the Routes for the App's Components
As we discussed in the
How Components are Rendered in React section, we can render a component in our app by adding it to the root `App` component's `return()` statement, creating a route for it or adding it to the body of another component that has a route created for it.
With the `PersonalHome` component, we just imported and added it to the `return()` statement of the root `App` component.
But for the `AboutMe` and `ContactMe` components, we will create a route for each one. The routing will be done inside the `App.js` component file.
But, first, we need to install a routing library/package to enable us configure routes for the app's components.
So, install that (from your terminal while inside the `personal` app's folder) with:
npm install react-router-dom
Or, if you are using `yarn` instead of `NPM`, use:
yarn add react-router-dom
Barring any Internet connection issues (or other errors that may pop up in your terminal), the package should be quickly and correctly installed for use in your `personal` app. It should now also have its own folder inside your app's `personal/node_modules/` folder.
Next, let's import some of the routing components of the `react-router-dom` package into our app's root `src/App.js` file.
After that, let's import the components we want to create routes for into the same root `src/App.js` component file. Since we will be configuring routes for the `PersonalHome`, `AboutMe` and `ContactMe` components, let's import those, like this:
import './App.css';
// Any additional imports go here too
// Other imports removed for brevity
// import the react-router-dom routing package
import {BrowserRouter, Routes, Route} from 'react-router-dom';
// import our app's custom components
import PersonalHome from './component/PersonalHome';
import AboutMe from './components/AboutMe';
import ContactMe from './components/ContactMe';
function App() {
return(
<PersonalHome />
)
}
export default App;
Finally, let's configure the routes for our `PersonalHome`, `AboutMe` and `ContactMe` components.
The routes we intend to configure are:
- `/`: This is the root route of the app. It is the first thing you see when you load up the app in the browser. This route will render the `PersonalHome` component.
- `/about`: This will render the `AboutMe` component.
- `/contact-me`: This is where the `ContactMe` component will get rendered.
So, open the `src/App.js` file and update it thus:
import './App.css';
// Any additional imports go here too
// Other imports removed for brevity
// import the react-router-dom routing package
import {BrowserRouter, Routes, Route} from 'react-router-dom';
// import our app's custom components
import PersonalHome from './component/PersonalHome';
import AboutMe from './components/AboutMe';
import ContactMe from './components/ContactMe';
function App() {
return(
<>
<PersonalHome />
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<AboutMe />} />
<Route path="contact-me" element={<ContactMe />} />
</Routes>
</BrowserRouter>
</>
)
}
export default App;
And, that's how you do routing in React. Your routes can also have URL parameters (such as, for example, to help decide which blog post to fetch and render in a `BlogPost` component using its "link", for instance, as the URL parameter).
But we don't have a need for routes with URL parameters in such a simple app. So, let sleeping dogs lie.
Our (very simple) app is almost done.
But, let's "refactor" it a bit.
As it currently stands, we can view our `<AboutMe />` component when we visit the `http://localhost:3000/about` URL and view the `<ContactMe />` component when we visit the `http://localhost:3000/contact-me/` URL in the browser.
But unless your app's user already knows that those two URL paths exist, there is now way of knowing they are there or even how to visit them.
So, let's fix that.
Let's update the `<PersonalHome />` component so that it links to both of those component's URLs.
Open the `src/components/PersonalHome.js` file and update it like this:
import React from 'react'
// import the {Link} component from the `react-router-dom' package
import { Link } from 'react-router-dom'
const PersonalHome = () => {
return (
<div>
<h3> Welcome to My Personal Site Online</h3>
<p>
"The Personal" is the web app where I live online.
It is my virtual home away from my brick-and-mortar home.
</p>
<p>
So, welcome!
</p>
<p>
By the way, you can learn more about me on my <Link to={`/about`}>About Me</Link> page.
</p>
<p>
You can also <Link to={`contact-me`}> contact me </Link> by sending me a message.
</p>
</div>
)
}
export default PersonalHome
To implement links between our React components, we:
- imported the `<Link />` component from the `react-router-dom` package that we installed earlier to use for routing
- used the `<Link />` component to link to other components (instead of using the usual HTML `<a href="">` tag and attribute.)
There are other routing components and hooks that come with the `react-router-dom` package, but we won't be going into details about their use cases here. If you want to dig in for more details, please, see the
react-router-dom documentation.
9. Styling React Components
You would have noticed that we were very simplistic when it came to styling our app's components. We only added inline styles in the `ContactMe` component. The others saw no styling whatsoever. That's on purpose, so that we can focus on learning the bare (but very important) basics of component development in React.
But, in a real-world app, you can style your components using one of five (5) ways:
- Inline: This is what we did in the `ContactMe` component using the `style` property of the HTML/JSX tags.
- External Stylesheet: This could be from a CSS framework (such as Bootstrap) or your own custom CSS stylesheets.
- JavaScript Styling Object: Where you write raw CSS inside a JavaScript object and use it inside your component's JSX markup.
- Styled Components: These are pre-styled React components that you can install and use in your app's components. Examples include `react-bootstrap`, `react-mdl`, etc.
- Dynamic Styling: Implemented using one of the first three styling options above.
For a detailed coverage of how to style components in your React apps, see my How to Implement Simple and Dynamic Styling in your React App guide.
10. Best Practices
As you develop more React apps, you will encounter more use cases, need to utilize a range of packages and libraries and come across edge cases that you will need to be creative about and think "outside the box" for, as they say.
Throughout these, you will learn the proper ways of creating apps, the myriad of approaches to making API calls and the different ways you can manage local and global state, configure routes and write automated tests for your React apps.
After all these, you will come away with more experience and an understanding (and appreciation) of the best ways to develop React apps (and web apps in general). These are known as best practices.
Here are a few best practices to keep in mind as you learn to develop more and more complex frontend (React) apps.
- Don't Mess with the Root `App` Component File: Your React app's root `App` component (in the `src/App.js` file) is not a place to write CSS styles, handle the complex logic for your app's global state, make API calls or to write the code and JSX markup for your "Home" component.
Keep the `App` component clean, simple and bug-free. Only use it to:
- import app-wide modules, stylesheets and libraries
- implement app-wide routing for your components
- wrap your app's components in the global context (provider) object
- and so on ...
But don't put calculations, JSX markup and UI styles in there. That's stuff that should got into your component or CSS files. Only use it for app-wide code and setup that can't be put into any other component or file.
- Keep it Simple and Progressive: When you first start out learning how to develop frontend apps using the ReactJS framework, you will start to hear (from forums, groups, newsletters, blog posts and everywhere else) about new "cool" things that just made another tool "obsolete" or a new way of doing things or <somethingElse/ >.
Don't fall for the "shiny object syndrome". Learn the basics, apply simple tools and then progressively learn more complex stuff and use more specialized tools and libraries to achieve better results. But don't take on so much so early in your learning journey.
Don't put lipstick on a pig.
Learning the newest version of that state management library will do you more harm than good if you haven't even learned about the variety of ways (and hooks and API) that React provides for managing both simple and complex state in your React app.
Then, learn how to properly use `useEffect()`, `useRef()` and other built-in React hooks before you go "shopping" for or "comparing" packages/libraries/frameworks to help you manage your app's "side effects."
The same thing goes for styling: Learn to use inline styles, then JavaScript Object styling, then external stylesheets before you resort to installing and using a "styled components" framework.
The same applies to making API calls: Learn to use the global `Fetch API` before you learn `axios` or other (more complex) tools.
And, so on. Keep your React learning journey simple and progressive and productive. Don't be that guy that knows a thing about everything but can't implement anything with any tool even if his life depends on it.
- Learn from the Official Docs: There are two ways you can learn any open source tool (package, library, framework, etc.): through _third-party tutorials (on Youtube, blog posts, workshops, etc.) or using the official documentation.
I can bet you that you will be better off first learning from the official docs (and any "get started" guides) that the creators of the framework/library/package have put together than you will from a favorite Youtuber or blogger. Many times, those tutorials are littered with the developer's tool bias, "shortcuts", "bad practices", "experience deficiency" and personal preference. (There are exceptions, I know. But the exceptions don't count in the general scheme of things).
So, avoid adopting another user's opinions, mistakes and worst practices and go for the official docs first. You will learn about the various APIs and tools available and any design decisions that went into developing various aspects of the framework.
These pieces of insights will help you better learn and use the framework. You will also know if (and when) you need to switch parts of the framework/library without breaking it.
So, learn from the official docs of whatever framework or library or package you are learning to use (and there will be dozens of them along the way).
Later on, you can supplement that knowledge with your own experience using it and the opinions and insights from other developers, Dev Youtubers, bloggers and members of your developer community.
- Develop More Apps More Often: What's better than watching every Youtube video or reading any blog post or reading all the official docs related to React (or whatever other library, package or framework you are using)? Developing more apps, that is!
The marker of how much you know and master a technology is not how much time you have spent learning it. It is about how much time and effort you put into perfecting those skills by creating as many apps as possible that implement the features and API of that technology (library, framework or package).
You should develop at least three apps for each skill (styling, state management, API calls, testing, etc.) that you want to master. Why at least 3 apps?
That is because:
- The first time you create an app around that skill, you will be referring to the official docs, other tutorials you have come across and your own personal notes.
You will also be googling the errors you get and will endup on StackOverflow and other developer blogs more often than you can imagine. So, your first app (to master that skill) is a rough ride, to say the least.
- The second app you create around that skill, you will encounter less bugs, fix more errors on your own (because you encountered and fixed them the first time around) and will be looking at the code from your first app.
You will also be referring to your "bug database" (that is, the notes you keep to document the errors and bugs you encountered during the first app's development and the solutions you used to fix those bugs and errors, including links to StackOverflow threads and forum discussions that were useful to you.)
But, by and large, you will be building the app with more experience, confidence and awareness of what will be popping up at you (in terms of gotchas, bugs, errors and warnings).
- The third app you build to master that skill, you will trigger much fewer bugs, fix most of the errors on your own and avoid more technical "gotchas" (silent bugs) and spend less time consulting your personal notes and "bug database".
At this point, you can talk about that library or framework and code apps using it almost without any technical reference (barring a few edge cases.)
So, yeah, build at least three apps around a skill (state management, styling, routing, API calls, testing, etc.) if want to really come close to mastering a skill. The more complex a skill (or its related library/framework) is, the more apps you should build around it.
And, when building an app, focus most of your energy on perfecting that skill and less of it on other skills. For example, if you are creating an app to master state management in React using the
Redux Toolkit, focus less on styling your components and creating complex routes and more on implementing the state management structure and logic of your app. Anything else should be secondary even if they are necessary.
Then, push your code to a repo you create for that app on your Github account. Then, link to that in your resumé (if you are looking for a job or consulting gig or just want to up your personal developer brand among your peers).
There are other best practices. But you will pick those up on your way up learning and developing more React apps.
Till next time, develop more awesome React apps to help make our world a better place for us all.
11. Technical Reference
Here are some resources to help you advance in your journey to learning how to develop React apps quickly and properly.