How to build a React useCounter and use Reducer counter app
Published: 2023-01-10 22:32:21


To start with, what is **React**?

**React** is a powerful and flexible JavaScript library that makes it easy to build complex and high-performance user interfaces. 

React allows developers to build reusable UI components and manage the state of their applications.


**How to Create a React Application**

**Note: In your local computer, you must install Node.** 

First, let's create a new React application using `create-react-app` in your command line, navigate to the `documents` directory where you want to create your app and run the following command:

```
npx create-react-app my-counter-app
```

This will create a new directory called 'my-counter-app' that contains the basic file structure for our React application.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7k0ngdmk5522kc6yil9.png)








Next, Using your VS code, launch 'the my counter app' file.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gk787qd037bog4lt7ven.png)

The `App.js` in the `src` directory is where we will build our counter application.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktos1yb7cw0reu3w1fp4.png).


Clicking on it will see the pre-written code created by React.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fuyh2indoze76q8yawhh.png)

To see the the pre built app by the pre-written code by **React**.

Go to your terminal,


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uaz3s5q2ytzrk1in444p.png)

go to the documents directory where our `my-counter-app` file that contains our **React** Application in our terminal. Follow these command lines in the terminal.

```
 cd documents

```



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lqgchze5ojfzilndioxk.png)

It will take you to the `documents` directory. From the `documents` directory, go to where our `my-counter-app` file for the **React** Application is. Follow these command lines in your terminal,

```
cd my-counter-app
```

it will take you to the `my-counter-app` file in your directory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnzgqttj9whlm2d6t6fk.png)




To run the development on the server, follow these command lines on your terminal.

```
npm run start
   or
npm start
```

The file will need to be successfully compiled, which will take a few minutes. After that, you can see my-counter-app in the browser. You should be directed to your browser where this should appear.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0abmkw4wwxhd1ytqjg4p.png)

when you go to your terminal, you should see this.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xggutnut5dzihxhu8dnm.png)


Return to your VS code after that and remove the codes from the `App.js` file in the `src` directory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xj6iyhc3gsxf59udyjub.png)

And your `my-counter-app` in the localhost:3000 will be empty.



The counter app will also include the following features..

- **Error Boundary**, to ensure that an error in a child component does not cause the entire application to crash.

- **React Router**,a library for React that enables you to manage routing within your application.

- The technique of optimizing a website or web application to increase its exposure and position in search engine results pages is known as **SEO**.

- A page that directs users to a broken **error page** 


Installing these packages is required in order to implement the added features to the counter application.

- **React Router**

- **React Error Boundary**

- **React Helmet Async**

Following these command lines will allow us to install them together.

```
npm install react-router-dom  react-helmet-async react-error-boundary.
```


Next, lets's create a new directory in the `src` directory called `hooks` and add a new file in the `hooks` called `useCounter.js`. This file  will contain the `useCounter` hook that we will use to manage the state of our counter. Here is how the `useCounter` file and hook  directory going to look:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/041hq1ny7el740fxdosi.png)



This hook use `usestate` hook to manage the counter, and expose `increment`, `decrement`, `multiply`, `input value` and the `count` value. we have to import it.  The `useCounter` hook's code is provided here.
 

```
import { useRef, useState } from 'react';

function useCounter() {
  const [count, setCount] = useState(0);

  const inputRef = useRef();

  const decrement = () => setCount((prevValue) => prevValue - 1);
  const increment = () => setCount((prevValue) => prevValue + 1);
  const multiply = () => setCount((prevValue) => prevValue * 9);
  const reset = () => setCount(0);
  const handleClick = () => setCount(inputRef.current.value);

  return {
    count,
    decrement,
    inputRef,
    handleClick,
    increment,
    multiply,
    setCount,
    reset,
  };
}

export default useCounter;

```

Now that we have our hook, we will create new directory in the `src` directory called `components`. Let's create a new file in the `components` directory called `CustomHookPage. js` to initialize our `useCounter` hook. How do we do that? we have to import it to be able to access it.

 In this file, we'll create a component that displays the current count and buttons to `increment`, `decrement`, `input any value`, `multiply`, and `reset` the count. 

```
import React from 'react';
import useCounter from '../hooks/useCounter';


const CustomHookPage = () => {
  const counter = useCounter(0);
  const {
    inputRef,
    count,
    handleClick,
    multiply,
    decrement,
    increment,
    reset,
  } = counter;

  return (
    <div>
   

      <div className="main-counter-container">
        <div className="counter-container">
          <div>
            <button onClick={increment}>
              Increment
            </button>
            <button onClick={decrement}>
              Decrement
            </button>
            <button onClick={multiply}>
              multiply by 9
            </button>
          </div>
           </div>{count}</div>

           <div>
            <p>
              <input ref={inputRef} type="number" />
              <button onClick={handleClick}>set value</button>
            </p>
          </div>

          <button
            onClick={reset}
          >
            Reset
          </button>
        </div>
      </div>
    </div>
  );
};

export default CustomHookPage;

```



Next, lets's create a another file in the `hooks` directory called 'useReducer.js'. This file  will contain the `useReducer` hook that we will use to manage the state of our counter. Here is how the `hooks` directory going to look when  the `useReducer` file is added:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zipisja06tl94w78uay.png)




This hook create a `useReducer` function that takes in the current `state` and an `action`, and returns the updated `state` based on the `action type`. In this case, our `state` will just be a single number representing the `count`, and our `actions` will be `increment`, `decrement`, `multiply`, and an `input value`. Here is the code.


```
const countReducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    case 'multiply':
      return { count: state.count * 3 };
    case 'setValue':
      return { count: action.value };
    default:
      return state;
  }
};

export default countReducer;

```




Now that we have another hook, let's initialize it in a new file in the `components` directory called `UseReducerPage.js`. How do we do that? we have to import it to be able to access it. 


In this file, we'll create a component that displays the current value of the counter, and `dispatch` function to send `actions` when user clicks the `increment`, `decrement`, `input value`, `multiply`, and `reset`. Here is code.




```


import React from 'react';
import useReducer from '../hooks/useReducer';

const UseReducerPage = () => {
  const [state, dispatch] = useReducer(countReducer, { count: 0 });

  const setValue = (value) => dispatch({ type: 'setValue', value });

  return (

      <div>
        <div>
          <div>
            <button
              onClick={() => dispatch({ type: 'increment' })}
            >
              Increment
            </button>
            <button
              onClick={() => dispatch({ type: 'decrement' })}
            >
              Decrement
            </button>
            <button
              onClick={() => dispatch({ type: 'multiply' })}
            >
              multiply by 3
            </button>
          </div>
          <div>{state.count}</div>

          <p>
            <input
              type="number"
              placeholder="input number"
              value={state.count}
              onChange={(e) => setValue(e.target.value)}
              onMouseOut={(e) => (e.target.value = '')}
            />
          </p>

          <button
            onClick={() => dispatch({ type: 'reset' })}
          >
            Reset
          </button>
        </div>
      </div>
    </div>
  );
};

export default UseReducerPage;

```



**What next?**


In our components directory, add an ErrorPage file. This component  will show users an error link.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2lwd4c6dqz6gpau0ue0.png)

We will create a function that return errors

```
import React from 'react';

const ErrorPage = () => {
  return (
    <div className="error-container">
        <h1>404 Page</h1>
        <p>This is an Error page.</p>
      </div>
    </div>
  );
};
export default ErrorPage;

```


In our components directory, add an Error Boundary file. In this component, we'll build a counter function that detects errors when  count exceeds a certain threshold. Additionally, a fallback function will be created in the components directory to return to home .

Error Boundary file. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kzs8virgrgfakvlkegs4.png)


In the Error Boundary component, we have to import the `Error Handler` from the Error Boundary package we installed to handle the error, we will also import `useRef` and `useState` before we create the function.

```
 import React from 'react';
import { useRef, useState } from 'react';
import { useErrorHandler } from 'react-error-boundary';


export default function ErrorBoundary() {
  
  const [state, setState] = useState(0);
  const [history, setHistory] = useState('');

  
  const HandleError = useErrorHandler();

  if (state > 5) {
    throw new Error('Exceeded count!');
  }
  const Increment = () => {
    try {
      if (state === 5) {
        throw new Error('Exceeded count!');
      } else {
        setState(state + +1);
      }
    } catch (e) {
      HandleError(e);
    }
  };
  const Decrement = () => {
    setState(state - 1);
  };
  const Reset = (prev) => {
    if (prev === 0) {
      setHistory(0);
    } else {
      setHistory(state);
    }
    setState((prev = 0));
  };

  const inputRef = useRef(null);
 

  function handleClick() {
    setState(inputRef.current.value - 0);
  }
  
  return (
    <section>
      <div>
        <h1>Error prone!</h1>
        <h3>
          Count limit for this counter is 5. Numbers above the 
    set limit throw
          is error
        </h3>
        <p>
          <input ref={inputRef} type="number" id="message" name="message" />
          <button onClick={handleClick}>set value</button>
        </p>
        <div>Count: {state}</div>
        <button onClick={Increment}>
          Increment
        </button>
        <button onClick={Decrement}>
          Decrement
        </button>
        <button onClick={Reset}>
          reset
        </button>
        <p>Your last count before you reset was: {history}</p>
      </div>
    </section>
  );
}

```

Fallback file.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62lmkqoshwbps67w079p.png)

In the `Fallback` component, we will create a function that returns to home page after error thrown.

```
import React from 'react';

export const Fallback = () => {
  const Return = () => {
    window.location.href = '/';
  };
  return (
    <div>
      <h1>Something went wrong!</h1>
      <p>Count limit exceeded!</p>
      <button onClick={Return}>Return to Home page</button>
    </div>
  );
};

```





In our components directory, add a `Home` file. Our useCounter and useReducer hooks, Error page, and Error Boundary will all be located on this page, which will serve as our home page.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/987kthc4i6gca4mih5k2.png)

We have to create a function for it.

```
import React from 'react';
import { Link } from 'react-router-dom';

const Home = () => {
  return (
    <div>
      <div>
        <h1>Hi, Welcome to my counter Project.</h1>
      </div>
    </div>
  );
};

export default Home;

```


Now, we have created:

- We have created our `useCounter` hook Counter
- we have created our `useReducer` hook Counter
- An `Error Page` that has a broken site.
- An `Error Boundary` page that handles count error
- A `Home` page that links every other.


**What next?**


We must import all of our components directory files into the empty `App.js` in order to see what we have created.

Also, in order to enable managing routing within what we have created in our application, we need to import React Router packages that we installed in the App.js file.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihq95as82wpyezpdtjov.png)



Then, we must create an App.js function that returns all imported components. Within that function, we must create a different function to handle errors, and log the associated information on the console.

We must enclose the imported components in the pre-installed React Router before returning the function. It contains nested routes. We'll discuss the reason for nested routes later.

We must wrap our Error Boundary to handle errors, fallbacks, and the error handler before wrapping our nested routes in the router.

Why are nested routes necessary?

Having a Route component inside the opening and closing tags of another Route component is known as nested routing.



When we do this, our App.js appears as follows:


```
 import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import CustomHookPage from './components/CustomHookPage';
import UseReducerPage from './components/UseReducerPage';
import Home from './components/Home';
import ErrorBoundary from './components/Errorboundary';
import { Fallback } from './components/Fallback';
import ErrorPage from './components/ErrorPage';


function App() {
  const errorHandler = (error, errorInfo) => {
    console.log('logging', error, errorInfo);
  };
  return (
    <main>
      <Router>
        <ErrorBoundary FallbackComponent={Fallback} onError={errorHandler}>
          <Routes>
            <Route path="/" element={<Home />} />;
            <Route path="/customhookpage" element={<CustomHookPage />} />;
            <Route path="/usereducerpage" element={<UseReducerPage />} />;
            <Route path="/errorboundary" element={<ErrorBoundary />} />;
            <Route path="/errorpage" element={<ErrorPage />} />;
          </Routes>
        </ErrorBoundary>
      </Router>
    </main>
  );
}

export default App;

```

To enable routing within our application, we added the paths to each component in the nested routes. As a result, we also need to add it as a link so that users may access the pages we created.

To accomplish this, we must navigate to each component of each page we generated and import the proper link from React Route.

Home page

We have to import it link and return it link in the Home component

```
import React from 'react';

//Imported Link
import { Link } from 'react-router-dom';

const Home = () => {
  return (
    <div >
      <div>
        <h1>Hi, Welcome to my counter Project.</h1>
          //Link returned in the function

         <Link to="/customhookpage">
          <button>custom hook page</button>
        </Link>
        <br />
        <br />
        <Link to="/UseReducerPage">
          <button>usereducer page</button>
        </Link>
        <br />
        <br />
        <Link to="/error">
          <button>Error boundary</button>
        </Link>
        <br />
        <br />
        <Link to="/errorpage">
          <button>error page</button>
        </Link>
      </div>
    </div>
  );
};

export default Home;
```

Error page

We have to import it link and return it link in the Error component

```
import React from 'react';
import { Link } from 'react-router-dom';

const ErrorPage = () => {
  return (
    <div className="error-container">
      <Link className="link-color" to="/">
        <button className="link-button">home</button>
      </Link>
      <div className="error">
        <h1>404 Page</h1>
        <p>This is an Error page.</p>
      </div>
    </div>
  );
};
export default ErrorPage;

```

Custom Hook page

We have to import it link and return it link in the Custom Hook Page component



```
import React from 'react';
import useCounter from '../hooks/useCounter';

//imported link
import { Link } from 'react-router-dom';


const CustomHookPage = () => {
  const counter = useCounter(0);
  const {
    inputRef,
    count,
    handleClick,
    multiply,
    decrement,
    increment,
    reset,
  } = counter;

  return (
    <div>
      <div>
          //returned link
        <Link className="link-color" to="/">
          <button>home</button>
        </Link>
        <Link className="link-color" to="/UseReducerPage">
          <button>usereducer page</button>
        </Link>
        <br />
        <br />
      </div>

      <div className="main-counter-container">
        <div className="counter-container">
          <div>
            <button onClick={increment}>
              Increment
            </button>
            <button onClick={decrement}>
              Decrement
            </button>
            <button onClick={multiply}>
              multiply by 9
            </button>
          </div>
          <div>{count}</div>

          <div>
            <p>
              <input ref={inputRef} type="number" />
              <button onClick={handleClick}>set value</button>
            </p>
          </div>

          <button
            onClick={reset}
          >
            Reset
          </button>
        </div>
      </div>
    </div>
  );
};

export default CustomHookPage;

```

UseReducer Page

We have to import it link and return it link in the UseReducer component

```
import React from 'react';
import countReducer from '../hooks/countReducer';
import { useReducer } from 'react';

//imported link
import { Link } from 'react-router-dom';


const UseReducerPage = () => {
  const [state, dispatch] = useReducer(countReducer, { count: 0 });

  const setValue = (value) => dispatch({ type: 'setValue', value });

  return (
    <div>
      
      <div>
        //returned link
        <Link to="/">
          <button>home</button>
        </Link>
        <Link to="/customhookpage">
          <button>custom hook page</button>
        </Link>
      </div>
      <div>
        <div>
          <div>
            <button onClick={() => dispatch({ type: 'increment' })}
            >
              Increment
            </button>
            <button
              onClick={() => dispatch({ type: 'decrement' })}
            >
              Decrement
            </button>
            <button
              onClick={() => dispatch({ type: 'multiply' })}
            >
              mulitiply by 3
            </button>
          </div>
          <div>{state.count}</div>

          <p>
            <input
              type="number"
              placeholder="input number"
              value={state.count}
              onChange={(e) => setValue(e.target.value)}
              onMouseOut={(e) => (e.target.value = '')}
            />
          </p>

          <button
            onClick={() => dispatch({ type: 'reset' })}
          >
            Reset
          </button>
        </div>
      </div>
    </div>
  );
};

export default UseReducerPage;

```


**What next?** 

After completing the building of our application, the following step is to import our React Helmet Async in our application to increase its exposure and position in search engine results.

Then import our App.js file to the root of our index.js directory.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gd7irlxsexm8cslhflm4.png)


**Summary**

we created a  useCounter and useReducer hook counter Application, that has pages link to Error Boundary, Error Page with a good SEO.


You can add your own UI.

source code: https://github.com/Seundev/react-pno6jr.git
Live link: https://react-pno6jr.stackblitz.io