How To Implement & Set Input Value with React Hooks in a Counter Application.
Tags: react, counter, usestate, usereducer
Published: 2023-01-09 13:25:45

Hi techies!
In this post, I will be putting you through on how to implement _set value_ function with _input tag_ and _button_ using the following React Hooks: **useState**, **useRef** and **useReducer.**

We will be working on two counters; one will be controlled by **useState** hook while the other will be controlled by **useReducer** hook.
The counters will be having the following functions: 

- Increment
- Decrement
- Reset
- Set Value/handleClick
- handleOnChange

**Counter 1: useState Hook**
The first thing to do here is to import the **useState** hook from react.

```
import {useState} from "react";
```
After importing the **useState** hook, the next thing to do is to set it up.

**useState** accepts two argument. The first one is a **_value to store the data_** of the state while the second argument is a **_function to update the data_** in the state value. We also set the default value to zero.

```
const [count, setCount] = useState(defaultValue || 0);
```
**_Functions and buttons_**
Now, we need to set the functions and buttons.
Before setting anything, we need to import one more hook – **useRef** hook. This hook is needed for our **_Set Value function_** and **_input tag_**.

```
import { useState, useRef } from "react";
```
After importing, we set it up by declaring an _inputRef_ value and initialize it to null.

```
const inputRef = useRef(null);
```
**_Declaring the functions_**

```
const increment = () => setCount((countValue) => countValue + 1);
const decrement = () => setCount((countValue) => countValue - 1);
const setValue = () => setCount(inputRef.current.value - `${count}`);
const reset = () => setCount(defaultValue);
```
_N.B:_ In the set value function, we use _**template literal**_ to deduct count from `inputRef.current.value` so that when the _inputed_ value is set to the `count` variable, and the increment or decrement button is triggered, it will update the `count` state starting from the inputed value instead of displaying the two values together.

Final code set up.

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

export default function App(defaultValue) {
 const [count, setCount] = useState(defaultValue || 0);
 const inputRef = useRef(null);

 const increment = () => setCount((countValue) => countValue + 1);
 const decrement = () => setCount((countValue) => countValue - 1);
 const setValue = () => setCount(inputRef.current.value - `${count}`);
 const reset = () => setCount(defaultValue);

return (
      <>
        <div className="counter__wrapper">
         <div className="counter-box">{count}</div>

          <div className="counter-btn-wrapper">
           <button
            disabled={count >= 20}
            className="counter__btn operation-btn"
            onClick={increment}
          > + </button>

          <button className="reset-btn" onClick={reset}>
            Reset
          </button>

          <button
            disabled={count <= 0}
            className="counter__btn operation-btn"
            onClick={decrement}
          > - </button>
        </div>
        <div className="set__value">
          <div className="input__value">
            <input ref={inputRef} name="number" type="text" placeholder="0" />
          </div>
          <button onClick={setValue}>Set Value</button>
        </div>
      </div>
   </>

)
}
```

**Counter 2: useReducer Hook**
As usual, we import **useReducer** from react.

```
import { useReducer } from "react";
```
**_Declare a default/initial state variable._**
Initialize it with a `counter` object set to zero and `input` object set to empty string.

```
const defaultState = { counter: 0, input: "" };
```
OR

```
const initialState = { counter: 0, input: "" };
```
_Note: You can declare your own preferred variable name._

Declare a `reducer` function with a `switch` statement. 
In the statement, we will be having five (5) cases and a default. The five (5) cases are:
- `“increment”:` to update the state of the counter by adding + 1
- `“decrement”:` to update the state of the counter by subtracting -1
- `“reset”:` to return the state of the counter to default value 0
- `“setvalue”:` to update the state of the input value to whatever the user inputs
- `“updatecounter”:` to update the state of the counter to the current value in the input

```
const defaultState = { counter: 0, input: "" };
const reducer = (state = { name: "" }, action) => {
  switch (action.type) {
    case "increment":
      return { ...state, counter: state.counter + 1 };
    case "decrement":
      return { ...state, counter: state.counter - 1 };
    case "reset":
      return defaultState;
    case "setvalue":
      return { ...state, input: action.payload };
    case "updatecounter":
      return { ...state, counter: action.payload };
    default:
      throw new Error("Invalid action type");
  }
};
```
**_Functions_**
- `increment` with dispatch type set to “increment”
- `decrement` with dispatch type set to “decrement”
- `reset` with dispatch type set to “reset”
- `handleOnChange` with event `(e)` in the call back function and - `dispatch` type set to `“setvalue”`. It will also have a `payload` set to `e.target.value`
- `handleClick` with dispatch type set to `“updatecounter”`. The `payload` will be set to `state.input` and deducting the `counter` with a **_template literal _**
```
dispatch({
      type: "updatecounter",
      payload: state.input - `${state.counter}`,
    });
```
 so that when the inputed value is set to the `counter`, and the `increment` or `decrement` is triggered, it will update the `counter` state starting from the inputed value instead of displaying the two values together.

**_Final code set up._**

```
import { useReducer } from "react";

const defaultState = { counter: 0, input: "" };

const reducer = (state = { name: "" }, action) => {
  switch (action.type) {
    case "increment":
      return { ...state, counter: state.counter + 1 };
    case "decrement":
      return { ...state, counter: state.counter - 1 };
    case "reset":
      return defaultState;
    case "setvalue":
      return { ...state, input: action.payload };
    case "updatecounter":
      return { ...state, counter: action.payload };
    default:
      throw new Error("Invalid action type");
  }
};

export default function App() {
  const [state, dispatch] = useReducer(reducer, defaultState);

  const handleClick = () => {
    dispatch({
      type: "updatecounter",
      payload: state.input - `${state.counter}`,
    });
  };

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

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

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

  const handleOnChange = (e) => {
    dispatch({ type: "setvalue", payload: e.target.value });
  };
return (
      <>
        <div className="counter-box">
            {state.counter}
          </div>
        
        <div className="counter-btn-wrapper">
          <button
            disabled={state.counter >= 20}
            className="counter__btn operation-btn"
            onClick={increment}
          > + </button>

          <button className="reset-btn" onClick={reset}>
            Reset
          </button>

          <button
            disabled={state.counter <= 0}
            className="counter__btn operation-btn"
            onClick={decrement}
          > - </button>
        </div>

        <div className="set__value">
          <div className="input__value">
            <input
              onChange={handleOnChange}
              value={state.input}
              name="number"
              type="text"
              placeholder="0"
            />
          </div>
          <button onClick={handleClick}>Set Value</button>
        </div>
      </>
)
};
```
That will be all for now.
Check out for the full code and style implementation in my github [repo](https://github.com/Adezb/Counter-App-Exam-Project)

You can as well follow me on [twitter](https://twitter.com/adezb_CEO)