A Custom Counter App

Written by Jimoh Ameerah.

Hi, my name is Ameerah, I'm currently a student at altschoolafrica in the Frontend engineering department. In this article, I'll be tagging you along on the journey of how I did my counter app.

It took time and hard work to achieve this project, but with help from a few friends, Alhamdulillah(praise be to God) it came out well.

ABOUT THE COUNTER

The counter app allows users to count with ease, it comes with an increment, decrement and reset button. When users have finished using the counter app, they go ahead to clear their count up by using the reset button.

This counter app was created with increment, decrement, reset, and setValue functions with a valid UI and Implement a combination of states with a useReducer that implements a counter with the four evident features in the custom hook - increment, decrement, reset, setValue. Implement a page for the custom hook, useReducer, 404, and a page to test error boundary and good SEO. (Question)

It was built using react, designed using CSS and also makes use of useReducer hook to manage state.

REACT

Since react was used in the process of making this custom counter app, let's learn a bit about it.

According to Wikipedia, React (also known as React.js or ReactJS) is a free and open-source front-end JavaScript library[3] for building user interfaces based on UI components. It is maintained by Meta (formerly Facebook) and a community of individual developers and companies.[4][5][6] React can be used as a base in the development of single-page, mobile, or server-rendered applications with frameworks like Next.js. However, React is only concerned with state management and rendering that state to the DOM, so creating React applications usually requires the use of additional libraries for routing, as well as certain client-side functionality.[7][8].

THINGS TO INSTALL BEFORE STARTING THE PROJECT.

  1. Make use of any text editor you are comfortable with, some example includes;
  • Sublime Text

  • Visual Studio Code

  • ICEcoder

  • Textmate

  • Atom

    and loads more.

    1. Node.js should be installed. You can install it by clicking on the link below.

      %[nodejs.org]

  1. Git should also be installed, for those who are new and don't know what Git is, According to Wikipedia, Git (/ɡɪt/)[8] is a distributed version control system: tracking changes in any set of files, usually used for coordinating work among programmers collaboratively developing source code during software development. Its goals include speed, data integrity, and support for distributed, non-linear workflows (thousands of parallel branches running on different

    systems). Git was originally

    authored by Linus Torvalds in 2005 for the development of the Linux kernel, with other kernel developers contributing to its initial development.[12] Since 2005, Junio Hamano has been the core maintainer. As with most other distributed version control systems, and unlike most client–server systems, every Git directory on every computer is a full-fledged repository with complete history and full version-tracking abilities, independent of network access or a central server.[13] Git is free and open-source software distributed under the GPL-2.0-only license.

    %[en.wikipedia.org/wiki/Git]

CODES USED

I created a reducer folder, this folder consists of;

  • CounterReducer.js

    ```javascript const CounterReducer = (state,action) => {

      switch(action.type) {
          case 'increment':
              return {count: state.count + 1};
              case 'decrement':
                  if(state.count === 0) {
                      return {count: 0};               
                  }
                  else return{count: state.count -1};
                  case 'reset':
                      return {count: 0};
                      default:
                          return state;
      }
    

    }

export default CounterReducer 
Footer
© 2023 GitHub, Inc.
Footer navigation
Terms
Privacy
Security
Status
@sheishareema
```
  • Counter.css
.butt:hover {
    background: linear-gradient(to bottom, #fb9e25 5%, #ffc477 100%);
    background-color: cornflowerblue;
}
.butt:active {
    position: relative;
    top: 1px;
}
.flex-center {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100vw;
    height: 100vh;
}
.flex-column {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
  • counterHook.js
import {useReducer } from 'react'
import CounterReducer from './CounterReducer';

const useCounterHook = () => {
    const initialState = { count: 0};
    const [state, dispatch] = useReducer(CounterReducer, initialState);

    const  increment = () => {
        dispatch({ type: 'increment'});
    }

    const decrement = () => {
        dispatch({ type: 'decrement'});
    }

    const reset = () => {
        dispatch({ type: 'reset'});
    }

    return { count: state.count, increment, decrement, reset };
}

export default useCounterHook;
  • CounterPage.jsx

      import React from 'react'
      import useCounterHook from './counterHook';
    
      const CounterPage = () => {
          const { count, increment, decrement, reset } = useCounterHook();
          return (
            <div className="flex-center">
              <div className='flex-column'>
                  <h1>Counter App</h1>
                <p>{count}</p>
                <button onClick={increment} className="butt">Increment</button>
                <button onClick={decrement} className="butt">Decrement</button>
                <button onClick={reset} className="butt">Reset</button>
              </div>
            </div>
          );
      }
    
      export default CounterPage
    

    Then comes the design created in a folder named 'App.css'

  • App.css

    ```css

    .butt {

      box-shadow: insert 0px 1px 0px 0px #fce2c1;
      background:linear-gradient(to bottom, cornflowerblue 5%, cornflowerblue 100%);
      background-color:cornflowerblue;
      border-radius:15px;
      border:2px solid cornflowerblue;
      display:inline-block;
      cursor:pointer;
      color:white;
      font-family:Arial;
      font-size:16px;
      font-weight:bold;
      padding:8px 18px;
      text-decoration:none;
      text-shadow:0px 1px 0px cornflowerblue;
      position: relative;
    

    } .butt:hover {

      background:linear-gradient(to bottom, cornflowerblue 5%, cornflowerblue 100%);
      background-color:cornflowerblue;
    

    } .butt:active {

      position:relative;
      top:1px;
    

    }

    .flex-center {

    display: flex;
    align-items: center;
    justify-content: center;
    width: 100vw;
    height: 100vh;
    

    } .flex-column {

    display: flex;
    flex-direction: column;
    gap: 1rem;
    

    } body {

      display: grid;
      place-items: center;
      height: 100vh;
      background: beige;
      padding: 0;
      margin: 0;
    

    } .flex-column h1 {

      color: cornflowerblue;
      font-size: 50px;
      position: inherit;
      top: 8%;
      left: 25%;
    

    } .flex-column p {

      text-align: center;
      border:4px solid cornflowerblue;
      border-radius:12px
    
}
```
  • App.js
import './App.css';
import CounterPage from './Reducer/counterPage';
import "./index.css";
//import ErrorBoundary from './ErrorBoundary';


function App() {
  return (
    // <ErrorBoundary>
    <CounterPage />
    // </ErrorBoundary>
  );
}

export default App;
  • Error Boundary: 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. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

    %[reactjs.org/docs/error-boundaries.html]

import React, {logErrorToMyService} 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
      logErrorToMyService(error, errorInfo);
      //render 404 page
      this.setState({ hasError: true});
    }

    render() {
      if (this.state.hasError) {
        // You can render any custom fallback UI
        return <h1>Something went wrong.</h1>;
        return <ErrorPage />
      }

      return this.props.children; 
    }
  }

export default ErrorBoundary;
  • Index.js

    ```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
```

README.md

# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `npm start`

Runs the app in development mode.  
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.

The page will reload when you make changes.  
You may also see any lint errors in the console.

### `npm test`

Launches the test runner in the interactive watch mode.  
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

### `npm run build`

Builds the app for production to the `build` folder.  
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.  
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `npm run eject`

**Note: this is a one-way operation. Once you eject**, you can't go back!

If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single-build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point, you're on your own.

You don't have to ever use `an eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However, we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

The above is very useful, take note of it.

LINK

The link below takes you to the counter app.

Click on this link.