Photo by Bernard Hermant on Unsplash
Technical Documentation For A Counter App Project Created In React
React is a Javascript library used for building interactive user interfaces. According to the official react website, react helps you design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
This creation of simple views for each state & updating just the right component is an integral part of this counter app project as we will see later.
Project Goals
To create a digital counter --similar to the ones you see in football games -- that has a default value of 0 but increases or decreases when we click an increment/decrement button. Or when Ronaldo enters.
At default state of 0
After it increases eight times.
An input field that allows us type in any value of choice ( excluding the mark of the beast pls) or use an up & down arrow key to increase & decrease any value in the field. And immediately we click setvalue
button , the digital counter automatically displays that number.
Value of 75 typed in the input
field but count
still shows 0 beacuse the setvalue
button hasn't been clicked yet.
Count
automatically updates to 75 because the setvalue
button was clicked.
Project Structure
You know how welding can be performed in the garage via different techniques --- well, it is the same way we can create my counter app
project i just showed you snippets of up there by using different techniques.
For this project, we will use a customhook technique & also use a useReducer hook technique to implement the same project. As in we will do it twice but with different techniques.
The counter app project will have four pages in total ----- The Hompage. CustomHook page. UseReducerHook page & Testing Error-Boundary Page.
Setting Up The Project
To create the project, we have to setup the development environment using what is called create react app
. This enviroment is like a big house with many rooms(folders) where all the coding happens. You can call it a garage where new cars are manufuctured if you like. In this case, we want to manufacture a counter app.
Now lets enter the garage that already contains all the specially built tools we will be needing to build the project. To do this we type the code below in our git bash terminal or windows shell terminal. I believe any terminal is fine, as long as it's not the MM2 terminal in Lagos.
npx create-react-app my-app
cd my-app
npm start
npx create-react-app my-app
prepares to usher us inside the garage.
my-app
appended to the end is your preferred new folder name you want to conatin your project. It can be named anything( you can name it counter-app
if you like).
cd my-app
or cd-counter-app
takes you inside the folder you just created.
npm start
opens up the garage doors.
Now that we are in the garage & have all these fancy tools laying around at our disposal, do not forget why we are here! To build. Not to engrave i miss you on your ex's Tesla with a rusted saw.
The Homepage
This is the first page that appears when you first visit a website or static page. To create the homepage I created a react component called Home
and exported it via export default Home
on the last line so i'll be able to call it up inside the root App.js folder later or anywhere else when i need it.
This is why they say react helps you create re-useable components that can re-used uncountable times. They stole this concept from my old boxers.
import React from "react";
import Seo from "./Seo";
const Home = () => {
return (
<div>
<Seo
title= 'A React Counter App project'
name= 'description'
description= 'A Beginner friendly react app project'
type='article'
/>
<h1>Welcome... This is the Landing Page for my ALT-SCHOOL counter react app project....</h1>
</div>
)
}
export default Home
How it looks.
I know my casual design looks far from Home but let's focus on the end game here.
The CustomHook Counter Page
Remember how i said earlier that components can be re-usable, well, functions too. A function that's re-usable is a Hook. Functions can be blocks of code that perform a specific task. And if you need that same task to be performed many times you could instead of re-writing it three or hundred times, make it a customhook.
This page below has a complete user interface that allows you increase
, decrease
, setvalue
& reset
the digital count to 0.
Here, I set the value of the count
to always show 0 by default. I also did the same for the input
field. This method of setting a default to 0 knowing it'll change later to something else is called state
management.
const [count, setCount] = useState(0);
const [input, setInput] = useState(0);
Creating the Increment
, Decrement
, setvalue
& reset
code logic.
const Increment = (event) => {
event.preventDefault()
setCount(count + 1)
}
const Decrement = (event) => {
event.preventDefault()
setCount(count - 1)
}
const Reset = (event) => {
event.preventDefault()
setCount(0)
setInput(0)
}
const HandleChange = (event) => {
setInput(event.target.value)
}
const SetValue = (event) => {
event.preventDefault()
setCount(input)
Creating the digital count
UI interface.
<h1> COUNT : {count}</h1>
Creating the Input field UI --- used bootstrap for styling.
<Form >
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label className="text-muted">SET VALUE BELOW:</Form.Label>
<Form.Control type="number" value={input} onChange={HandleChange} />
</Form.Group>
</Form>
Putting it all together.
import { useState } from "react";
import { Button, Form } from "react-bootstrap"
function CustomCounter() {
const [count, setCount] = useState(0);
const [input, setInput] = useState(0);
const Increment = (event) => {
event.preventDefault()
setCount(count + 1)
}
const Decrement = (event) => {
event.preventDefault()
setCount(count - 1)
}
const Reset = (event) => {
event.preventDefault()
setCount(0)
setInput(0)
}
const HandleChange = (event) => {
setInput(event.target.value)
}
const SetValue = (event) => {
event.preventDefault()
setCount(input)
}
return (
<div className="container">
<h1> COUNT : {count}</h1>
<Form >
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label className="text-muted">SET VALUE BELOW:</Form.Label>
<Form.Control type="number" value={input} onChange={HandleChange}/>
</Form.Group>
</Form>
<div className="d-grid gap-5">
<Button variant="outline-warning" size="lg" onClick={Increment}> Increment</Button> {' '}
<Button variant="outline-danger" size="lg" onClick={Decrement}> Decrement </Button>{' '}
<Button variant="outline-danger" size="lg" onClick={Reset}> Reset</Button> {' '}
<Button variant="outline-warning" size="lg" onClick={SetValue}> SetValue</Button> {' '}
</div>
</div>
);
}
export default CustomCounter;
The useReducer Hook Counter Page
The useReducer is an inbuilt react hook that lets you add a reducer to your component. The reducer bascially helps you manage state by specifying how it gets updated.
To be able to use it, we must import it. React also stole this concept from Nigeria's economy.
import React from 'react'
import { useReducer } from "react";
Setting the deafult values ( or initial state
) of the digital count
& input
field to always show 0 by default.
const initialState = { count: 0, input: 0 }
const [state, dispatch] = useReducer(reducer, initialState)
Using the default value( or initial state
) of count
to implemente the increase
, decrease
, setvalue
& reset
code logic.
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 }
case 'decrement':
return { ...state, count: state.count - 1 }
case 'reset':
return { input: state.input * 0, count: state.count * 0 }
case 'setvalue':
return { ...state, count: action.newInputValue }
case 'storeInput':
return { ...state, input: action.payload }
default: {
return state
}
}
}
Creating the digital display count.
<h1> COUNTER: {state.count} </h1>
Creating the input field.
<Form.Label className="text-muted">SET VALUE BELOW</Form.Label>
It's pertinent to note that useReducer comes with a dispatch functions that allows you to update the state
( default or initial value) to something else. Below, I used it inside the respective buttons to effect the desired change ( increase, decrease, reset & setvalue when clicked.
<Button onClick={(() => dispatch({ type: 'increment' }))}> plus </Button>
<Button onClick={(() => dispatch({ type: 'decrement' }))}> minus </Button>
<Button onClick={(() => dispatch({ type: 'reset' }))}> Reset</Button> {' '}
<Button onClick={(() => dispatch({ type: 'setvalue', newInputValue: state.input }))}>setvalue</Button> {' '}
How the page looks.
Testing Error Boundary Page
Error boundaries are react components that catch errors anywhere in any of the elements that make-up a particluar page, register the error & display what's called a fall-back Ui instead of the component that crashed. Essentially, rather than show you your shame, how about a quiet Go back Home button instead.
Implementing the error boundary code & exporting it so it can re-useable where it is deem fit.
import React from 'react';
import ErrorNavigate from './ErrorNavigate';
import { Button } from 'react-bootstrap';
export class ErrorBoundary extends React.Component{
constructor(props) {
super(props);
this.state = { error: null}
}
componentDidCatch(error, errorInfo){
console.log(error, errorInfo);
}
static getDerivedStateFromError(error){
return { error}
}
render () {
if (this.state.error){
return (
<div className='card-box'>
<div className='card-content'>
<h3 className='the-error'>error(cannot display component's content)!Something went wrong HERE!
<ErrorNavigate/>
</h3>
</div>
</div>
)
}
return this.props.children;
}
}
export default ErrorBoundary;
Creating a Testing Error boundary page which contains four card components( comp 1, comp2, comp3, comp4) to test if the error boundary works. First, let's import it.
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
Making an error display in some cards (comp 2 & comp 4) & allowing others to display fully without catching errors. The aim is here is just to show that some cards are catching errors (then display a fallback Ui) while some are okay. Sigh.... isn't that life in a nutshell? Anyways, i digress.
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
import {Form, Button} from 'react-bootstrap'
const Comp1 = () => {
return (
<div className="card-box">
<div className="card-content">
<h2 >fIRST COMPONENT</h2>
<h3 className="text-muted">I'm displaying the content inside this first card component to show that the error boundary works. The throw error does'nt catch it</h3>
</div>
</div>
)
}
const Comp2 = () => {
throw new Error('error')
return (
<div>
<p>Displaying Second component</p>
</div>
)
}
const Comp3 = () => {
return (
<div className="card-box">
<div className="card-content">
<h2>Third COMPONENT</h2>
<h3 className="text-muted">I'm displaying the content inside this third card component to show that my error boundary works. The throw error does'nt catch</h3>
</div>
</div>
)
}
const Comp4 = () => {
throw new Error('error')
return (
<div>
<h1>Displaying Fourth component</h1>
</div>
)
}
const TestErrBoundary = () => {
return (
<div className="big-box">
<Comp1/>
<ErrorBoundary><Comp2 /></ErrorBoundary>
<Comp3/>
<ErrorBoundary><Comp4 /></ErrorBoundary>
</div>
)
}
export default TestErrBoundary
How the page looks.
The Navigation Menu.
Creating the navigation menu that contains all the four pages's clickable headers.
import React from 'react';
import { Nav, Navbar, NavLink } from "react-bootstrap";
import { Link } from "react-router-dom";
const Navplace = () => {
return (
<Navbar collapseOnSelect expand="sm" bg="dark" variant="dark">
<Navbar.Toggle aria-controls="navbarScroll" data-bs-toggle="collapse" data-bs-target="#navbarScroll" />
<Navbar.Collapse id="navbarScroll">
<Nav>
<NavLink eventKey="1" as={Link} to="/">Home</NavLink>
<NavLink eventKey="2" as={Link} to="/customhook">CustomHook</NavLink>
<NavLink eventKey="3" as={Link} to="/usereduce">UseReducer</NavLink>
<NavLink eventKey="4" as={Link} to="/testingerror">Testing-error</NavLink>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
export default Navplace;
How it looks
All four pages & Navigation menu were created as seperate componets and exported as export default.
Then were all imported into the main App.js
root folder for rendering on the Ui.
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import './App.css';
import CustomCounter from "./Components/customcounter";
import Useddreduce from "./Components/usereducer";
import NavBar from "./Components/Navlink";
import Home from "./Components/Home";
import ErrorPage from "./Components/ErrorPage";
import TestErrBoundary from "./Components/TestErrBoundary";
function App() {
return (
<div>
<Router>
<NavBar/>
<Routes>
<Route path= "/" element={ <Home/> }/>
<Route path= "/customhook" element={ <CustomCounter/> }/>
<Route path= "/usereduce" element={ <Useddreduce/> }/>
<Route path= "/testingerror" element={ < TestErrBoundary/> }/>
<Route path= "*" element={ < ErrorPage/> }/>
</Routes>
</Router>
</div>
);
}
export default App;
To display each page as a standalone when any of the navigation menu options is clicked, we use what's called a react router. It helps route pages appropraitely.
We first import it from a react package called react router dom.
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
Then we tell the browser to open any particular page (Route
) depending on the particular Nav bar menu element we click on.
<Router>
<NavBar/>
<Routes>
<Route path= "/" element={ <Home/> }/>
<Route path= "/customhook" element={ <CustomCounter/> }/>
<Route path= "/usereduce" element={ <Useddreduce/> }/>
<Route path= "/testingerror" element={ < TestErrBoundary/> }/>
<Route path= "*" element={ < ErrorPage/> }/>
</Routes>
</Router>
Remember we have just four pages. There's no page that exits as * , this means there's no path
to get to that non existent page. As a result, an error page would always display when a user tries to manually use "/
" to visit a page that's not any of the four pages.
Notice the "jk" in the address bar. My Project has no such page. As a result, this error page with a fall back UI
My project has a page where I used useReducer
hook to implement a counter app, so it takes me to that page when I manually navigate to the page using "/
".
Conclusion
That's the technical summary of how i implemented my react counter app project as a beginner in react. Hopefully with time & practise i'll write better code.
My biggest take-away from this project is the fact that the package that's responsible for seperating pages into standalone individuals ends with dom
, which is kind of shocking cos he always yapped about family. He might be fast, but i am furious.