Creating a Counter App using custom hook in React.js with Increment, Decrement, Reset, and Set Value functions.
I worked on a Counter App last year which was an exam project for the Frontend Engineering course I enrolled for at AltSchool Africa. The Counter App is a useful e-commerce tool that helps in managing the number of items in a cart. It is a powerful productivity app that can also be deployed in counting people, occurrences, instances, repetitions, and anything else.
Technical Details.
Here’s a list of what I needed to implement in the project:
. Increment, decrement, reset and set-value functions
. Custom hook
. Error-boundary; and
. SEO
Working on this project exposed me to growth. I kickstarted the project by surfing the internet and watching some YouTube videos. Then, I installed my React app using the command npx create-react-app counter-app using Vscode as my IDE. While the installation was done, I built my UI and created a component folder which contained my route, hook and error pages.
In addition, I created a custom useCounter hook that utilizes the useReducer hook to manage state in the counter app. This custom hook was used to create the increment, decrement, reset and set counter values.
import React, { useReducer, useRef } from 'react';
import useCounter from '../Pages/useCounter'
const initialState = {count:0} ;
const reducer = (state, action) =>{
switch (action.type) {
case "Increment":
return {count: state.count + 1};
case "Decrement":
return {count: (state.count) - 1};
case "Reset":
return {count: (state.count = 0)};
case "Set Value":
return {count: Number(action.value)}
default:
return {count: state.count};
}
}
function useCounter(dispatch, inputRef) {
const handleIncrement = () => {
dispatch({
type:'Increment',
})
}
const handleDecrement = () => {
dispatch({
type:'Decrement'
})
// setState(state => state - 1)
}
const handleReset = () => {
dispatch({
type:'Reset'
})
// setState(state => state = 0)
}
const handleSetValue = () => {
if (inputRef.current.value) {
dispatch({
type: 'Set Value',
value: inputRef.current.value,
});
inputRef.current.value = " ";
}
return;
};
return {handleIncrement, handleDecrement, handleReset, handleSetValue};
}
export default useCounter;
To use the custom hook, I imported the hook into the counter component and destructured the returned object.
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const inputRef = useRef();
const { handleIncrement, handleDecrement, handleReset, handleSetValue } = useCounter(dispatch, inputRef);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
<button onClick={reset}>Set Valuet</button>
</div>
);
}
export default Counter;
At this juncture, I was elated about my progress. Implementing Error boundary into the project was a piece of cake by simply using the command npm install react-error-boundary as I created a React.Component
class and included a componentDidCatch
lifecycle method.
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
In order to use the error-boundary component, I wrapped it around the routes I wanted it to protect in my App.js. This way, errors thrown in any of the routes will be caught by the error-boundary.
import './App.css';
import Home from './Components/Home';
import Counter from './Components/Counter';
import Error from './Pages/Error';
import ErrorBoundary from './Pages/ErrorBoundary';
import { BrowserRouter, Routes, Route} from 'react-router-dom'
import Navbar from './Components/Navbar'
function App() {
return (
<div className='wrapper'>
<ErrorBoundary>
<BrowserRouter>
<Navbar />
<Routes>
<Route path='/' element={<Home />} />
<Route path='/counter' element={<Counter />} />
<Route path='*' element={<Error />} />
</Routes>
</BrowserRouter>
</ErrorBoundary>
</div>
)
}
export default App
Moving on to the last step, I implemented the SEO (Search Engine Optimization) that helps search engines to understand the content of apps and improve its ranking in search results. I used the command npm install -save react-helmet.
When I was done with all the implementation, I deployed my code to GitHub and hosted it on vercel.com:
https://altschool-exam-project-ruby.vercel.app/
As much as I felt happy working on this project, I won’t hide the fact that I enjoyed every bit of the journey. With consistency and determination, nothing is unachievable.
Thank you for sparing time to read my article. By the way, it’s my first on Medium. See ya again!