React js is a javascript library for building awesome ui.
In this blog post, i would be sharing how i was able to build a simple calculator using the useReducer Hook, useState hook.
Setting up the Application.
To bootstrap the application we use create react app.
npx create-react-app react-calculator
The second thing to do is to remove the boilerplate code and install the necessary dependencies
npm i react-router-dom helmet
i wanted my app to have a good seo ranking so i install helmet.
i also wanted to be able to have different routes hence the need for react router dom.
i set up error boundary on my code to ensure that even if my app had an error it would not entirely break.
any route that is not accounted for would fall into the catch all route or the error page.
here is a code snippet of how my main.jsx looks like
import Counter from "./Counter";
import { Route, Routes } from "react-router-dom";
import Error from "./Error";
import { Helmet } from "react-helmet";
import ErrorBoundary from "./ErrorBoundary";
function App() {
return (
<>
<Helmet>
<title>reduce counter</title>
<meta name="description" content="reducer counter" />
</Helmet>
<ErrorBoundary>
<Routes>
<Route path="/" element={<Counter />} />
<Route path="*" element={<Error />} />
</Routes>
</ErrorBoundary>
</>
);
}
export default App;
import { useReducer, useState } from "react";
import { reducer, initialState } from "./countReducer";
import React from "react";
import {
INC_COUNT,
DEC_COUNT,
RESET_COUNT,
ADD_VALUE,
REDUCE_VALUE,
} from "./types";
import "./counter.css";
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const [input, setInput] = useState(+0);
const data = (e) => {
setInput(+e.target.value);
};
if (input >= 10000) {
throw new Error("value is too big");
}
return (
<div className="App">
<div className="container">
<div className="count-bar">
<label htmlFor="" className="count-bar-lebel">
total
</label>
<p>{state.number}</p>
</div>
<div className="count-text">
<label htmlFor="" className="input-label">
add any number
</label>
<input
type="number"
onChange={data}
className="count-input"
placeholder="enter any number"
value={input}
/>
</div>
<div className="values">
<button
onClick={() => {
dispatch({ type: ADD_VALUE, payload: input });
setInput(0);
}}
>
add any number
</button>
<button
onClick={() => {
dispatch({ type: REDUCE_VALUE, payload: input });
setInput(0);
}}
>
remove any number
</button>
</div>
<div className="values">
<button onClick={() => dispatch({ type: INC_COUNT })}>
add (+1){" "}
</button>
<button onClick={() => dispatch({ type: DEC_COUNT })}>
reduce (-1)
</button>
</div>
<div className="reset">
<button onClick={() => dispatch({ type: RESET_COUNT })}>
reset (0){" "}
</button>
</div>
<p className="warning">numbers greater than 10000 throws an error</p>
</div>
</div>
);
};
export default Counter;
The first thing i did when creating this component was to import both useState and useReducer from react,
then imported initialState and the reducer function from countReducer.
useRreducer takes in both the reducer function and the initialState.
state and dispatch are destructured from the useReducer hook.
I created my action types from a seperate file to aviod error.
The app has different action types namely
- INC_COUNT,
- DEC_COUNT,
- RESET_COUNT,
- ADD_VALUE,
- REDUCE_VALUE,
INC_COUNT is responsible for adding one to the state value.
DEC_COUNT is responsible for removing one from the state value.
RESET_COUNT is responsible for resetting the count value to zero.
ADD_VALUE adds any desired value to the state.
REDUCE_VALUE removes any amount from the state
How the logic works
whenever any of the buttons are clicked, there is an onClick handler that contains the dispatch function that is triggered
this is how the reducer function looks like
import {
INC_COUNT,
DEC_COUNT,
RESET_COUNT,
ADD_VALUE,
REDUCE_VALUE,
} from "./types";
export const initialState = {
number: 0,
};
export const reducer = (state, action) => {
switch (action.type) {
case INC_COUNT:
return {
...state,
number: state.number + 1,
};
case DEC_COUNT:
return {
...state,
number: state.number - 1,
};
case RESET_COUNT:
return {
number: 0,
};
case ADD_VALUE:
return {
...state,
number: state.number + action.payload,
};
case REDUCE_VALUE:
return {
...state,
number: state.number - action.payload,
};
}
};
Top comments (0)