How I created a set counter, using React Custom Hooks (useState and useReducer)
Introduction:
React is a flexible and powerful open-source library for developing rich client-side applications, It takes cues from the world of server-side development and applies them to HTML elements. React creates a foundation that makes building rich web applications easier, see more on react documentation.
This write-up involves how I create a counter app with custom hooks (useState and useReducer) which involves increment, decrement, reset and setValue also including the use of react-router and error boundaries pages.
Custom hooks:
A custom hook is a JavaScript function. the name custom hook starts with "use" which can call other Hooks. Building custom Hooks allow you to extract component logic into reusable functions. example useState, useReducer, useEffect etc.
Counter with useState:
useState () is a functional component for setting and retrieving state. Hook state is the new way of declaring a state in React app. The example below shows the function of useState in my increment and decrement counter app.
import React from "react";
function CountOne() {
const inputRef = useRef(null);
const [updated, setUpdated] = useState(0);
const handleIncrement = (event) => {
event.preventDefault();
setUpdated (prev => prev + 1);
};
const handleDecrement = (event) => {
event.preventDefault();
setUpdated (prev => prev - 1);
};
const handleReset = (event) => {
event.preventDefault();
setUpdated (prev => prev = 0);
};
const handleClick = (event) => {
event.preventDefault();
setUpdated(inputRef.current.value);
};
return (
<div>
<input onChange={handleClick}
ref={inputRef}
type="number"
id="message"
name="message"
placeholder='setValue'
/>
<h2 className='count'>count: {updated}</h2>
<button className="action-btn" onClick {handleDecrement}>Decrement</button><br/><br/><br/>
<button className="action-btn" onClick={handleReset}>Reset</button><br/><br/><br/>
<button className="action-btn" onClick={handleIncrement}>Increment</button><br/><br/><br/>
</div>
);
}
export default CountOne;
Counter with useReducer:
The useReducer hook is used to store and update the state, just like the useState hook, it accepts a reducer function as it's first parameter and the initial state as the second.
useReducer returns an array that holds the current state value and a dispatch function to which you can pass an action and later invoke it: example of useReducer using my increment and decrement counter app;
import { useReducer, useRef } from 'react';
function countReducer(initialState = 0, action) {
if (action === 'increment') {
return initialState + 1;
} else if (action === 'decrement') {
return initialState - 1;
} else if (action === 'reset') {
return initialState = 0;
}else{
return initialState;
}
}
function Count() {
const inputRef = useRef(null);
const [count, dispatch] = useReducer(countReducer, 50);
return (
<div className="App">
<span className="count">count: {count}</span><br/><br/>
<div className="card">
<button onClick={() => dispatch('increment')}>Increment</button><br/><br/><br/>
<button className='reset' onClick={() => dispatch('reset')}>Reset</button><br/><br/><br/>
<button onClick={() => dispatch('decrement')}>Decrement</button>
</div>
</div>
);
}
export default Count;
React Router
Routing is a process in which a user is directed to different pages based on their action or request. React Router is mainly used for developing Single Page Web Applications with multiple routes. When a user types a specific URL into the browser, if the URL path matches any 'route' inside the router file, the user will be redirected to that particular route.
Implementation of React Router in my web application with the following step;
Step 1: installing react-router-dom@6 in my vscode terminal.
npm i react-router-dom@6
Step 2: Import <BrowserRoute> in my index.Js file and wrap it in my root app component.
`import { BrowserRouter } from "react-router-dom";`
`const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ErrorBoundary>
<BrowserRouter>
<React.StrictMode>
<HelmetProvider>
<App />
</HelmetProvider>
</React.StrictMode>
</BrowserRouter>
</ErrorBoundary>
);
Step 3: importing Route and links in my components:
`import React from "react";`
`import { Route, Routes } from "react-router-dom";`
`function App() {`
`return (<>
`<section class="main">`
<Routes>
<Route path="/" element={<Home />} />
<Route path="/counter1" element={<Counter1 />} />
<Route path="/counter2" element={<Counter2/>} />
<Route path="/error" element={< TestErrorPage/>}/>
<Route path="*" element={<Error404/>} />
</Routes>
</section>
</>
);
}
export default App;
Error boundaries:
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Implementing error boundary in my counter web applications with the following steps.
Step 1: I wrapped the error boundary in my index.js file.
`import React from 'react';`
`import ErrorBoundary from './AltExams/ErrorBoundary';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ErrorBoundary>
<React.StrictMode>
<App />
</React.StrictMode>
</ErrorBoundary>
);
Step 2: Created an error boundaries component.
`import React from "react";`
class ErrorTesting extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(({ counter }) => ({
counter: counter + 1
}));
}
render() {
if (this.state.counter === 1) {
// Simulate a JS error
throw new Error('I crashed!');
}
return <>
<h2>{this.state.counter}</h2>
<button className="errorBtn" onClick={this.handleClick}>Click me</button>
</>
}
}
import * as React from "react";
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
}
componentDidCatch(error, errorInfo) {
// Catch errors in any components below and re-render with error message
this.setState({
error: error,
errorInfo: errorInfo,
});
}
render() {
if (this.state.errorInfo) {
return (
<>
<br/><br/><br/>
<div className="center"> <a className="switchs" href="/">Refresh page</a>
<h1>Something went wrong.</h1>;
<details style={{ whiteSpace: "pre-wrap" }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
</>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Conclusion:
This article is an overview of how I create a counter app using custom hooks(useState and useReducer). With the implementation of React Router which is used to navigate between pages on the website and Error boundary page. During my Second semester exams at AltSchool Africa.