Table of Content
- Introduction
- Project overview
- Getting Started
- Integrating the Counter Page
- Error Boundary page
- Custom 404 Page
- About Page
- Conclusion
Introduction
Firstly let us see the meaning of custom hook. Custom Hook is a more advanced feature of React. It can let you reuse stateful logic without changing your component hierarchy. It will also make your component code more readable and easier to maintain.
Task
Setup a custom counter hook with increment, decrement, reset, setValue functions with a valid UI. Implement a page for the custom hook, 404, and a page to test error boundary.
Project Overview
I built this web application with some important features and implementation which include;
- An input field to set the counter to any starting value.
- Buttons that can automatically increase or decrease the counter by a value more or less than 1 when clicked.
- A reset button that automatically set count back to 0
- Implementing a 404 Page, Error Boundary, and About Page.
- A clean and user friendly UI.
- Routing of pages.
Getting Started
Before i began the project, i already had prior knowledge and was familiar with the basics of React Hooks and how to create a custom hook.
Firstly, i opened my terminal and i input the command npm create-vite@latest
followed by the project name, i named mine My-Counter App.
Create react app
npm create-vite@latest my-react-app
cd my-react-app
npm install
npm run dev
Install Dependencies
The next thing i did was to install the dependency i will be needing for my project, react router
, which will enables me to implement dynamic routing in my web app.
npm i react-router-dom
Setup
In my newly created app i opened the src folder and i deleted the asset and App.css files.
Then i went ahead to create another folder in the src folder which i named Components, in the components folder i created 6 files named: counter.jsx
, useCounter.jsx
, errorBoundary.jsx
, notFound.jsx
and about.jsx
.
Then i set up my react-router
in the App.jsx
file
import { Routes, Route, NavLink } from "react-router-dom";
import Counter from "./components/Counter";
import About from "./components/About";
import NotFound from "./components/NotFound";
import TestError from "./components/TestError";
import './index.css'
function App() {
return (
<div className="App">
<header className="nav-header">
<NavLink className="counter-logo" to="/"><img src="./images/counter-logo.png" alt="logo" />
Counter
</NavLink>
<nav>
<NavLink className="nav-link" to="/test-error-boundary">Error Boundary</NavLink>
<NavLink className="nav-link" to="/about">About</NavLink>
</nav>
</header>
<main>
<Routes>
<Route path="/" element={<Counter />} />
<Route path="/about" element={<About />} />
<Route path="/test-error-boundary" element={<TestError />} />
<Route path="*" element={<NotFound />} />
</Routes>
</main>
<footer>
<p className="text-align-center">
Copyright © 2024 Ayaoba. <br />
All rights reserved.
</p>
</footer>
</div>
)
}
export default App;
Counter Page
Implementing useCallback
At the top of the Counter.js.
file i imported the useCallback hook from React.
The React useCallback Hook will returns a memoized callback function. which will allows us to isolate resource intensive functions so that they will not automatically run on every render.
import { useCallback } from 'react'
import useCounter from '../components/UseCounter';
function Counter() {
const { increment, decrement, reset, setValue, count } = useCounter();
const handleSubmit = useCallback(
(event) => {
event.preventDefault();
setValue(event.target.newValue.value);
event.target.newValue.value = "";
},
[setValue]
);
return (
<div className="counter">
<h1>{count}</h1>
<div className='counter-button'>
<button className='counter-btn_plus button-shadow' onClick={() => increment()}><img src="./images/plus.png" alt="plus" /></button>
<button className='counter-btn_reset button-shadow' onClick={() => reset()}><img src="./images/reset.png" alt="reset" /></button>
<button className='counter-btn_minus button-shadow' onClick={() => decrement()}><img src="./images/minus.png" alt="minus"/></button>
</div>
<form onSubmit={handleSubmit}>
<input className='new-value' name="newValue" type="tel" placeholder="New value" />
<button className="btn-set-value">Set value</button>
</form>
</div>
);
}
export default Counter;
Implementing useReducer
In the useCounter.jsx
file I implemented the UseReducer method.
useReducer is a React hook that allows us to manage state in a simple and consistent way. This Hook accepts two arguments. It returns the current state and a dispatch method.
import { useReducer, useCallback } from "react";
const useCounter = () => {
const ACTIONS = {
INCREASE: "increase",
DECREASE: "decrease",
RESET: "reset",
SET_VALUE: "setValue",
};
function getValue(value, count) {
let result = count;
if (!value) {
result = count;
} else if (Number.isFinite(+value)) {
result = +value;
}
return result;
}
function reducer(count, action) {
switch (action.type) {
case ACTIONS.SET_VALUE:
return getValue(action.value, count);
case ACTIONS.INCREASE:
return count + 1;
case ACTIONS.DECREASE:
return count -1;
case ACTIONS.RESET:
return 0;
default:
return count;
}
}
const [count, dispatch] = useReducer(reducer, 0);
const increment = useCallback(() => {
dispatch({ type: ACTIONS.INCREASE });
}, [ACTIONS.INCREASE]);
const decrement = useCallback(() => {
dispatch({ type: ACTIONS.DECREASE });
}, [ACTIONS.DECREASE]);
const reset = useCallback(() => {
dispatch({ type: ACTIONS.RESET });
}, [ACTIONS.RESET]);
const setValue = useCallback(
(value) => {
dispatch({ type: ACTIONS.SET_VALUE, value });
},
[ACTIONS.SET_VALUE]
);
return { count, increment, decrement, reset, setValue };
};
export default useCounter;
Error Boundary page
I opened the errorBoundary.jsx
file and i created an Error boundary component to catch JavaScript errors anywhere in its child component tree, log the errors, and display a fallback UI instead of the component tree that crashed.
Custom 404 Page
In notfound.jsx
i added a custom 404 page that will display when the server cannot find a page the user has requested.
About Page
Finally, in About.jsx
i added an About page that consist of relevant information on how to navigate though the counter app
.
Conclusion
This project was my second semester examination Project at AltSchool Africa.
You can check out the live site of my counter app.
And also, the GitHub repo to the application.
Thanks for Reading.
Top comments (0)