From React Class component to Functional component with hooks

How to create a React counter with the useReducer hook?

In the previous article, we have studied thoroughly the code structure when using the React useReducer hook. We have discovered:

Now that we have understood which are all the different part of the coding structure and how they interact, we can create a useReducer Counter.

Summary

Before creating the useReducer hook counter we will check what elements the Counter will display and will review the useState Simple Counter code from a previous article. Then will propose two different useReducer Counter coding solutions.

Informations about the Counter

This counter render will be the same as the React useState Simple Counter we coded in a previous article. You can find this Simple Counter code below, in this article, if you need to refresh your memory.

So, this counter component will display:

  • 3 buttons: “-” or “decrement”, “+” pr “increment”, “reset”;
  • a “Count: ” information which will be initialized at “0” and will be updtated every time one of 3 above button is clicked.

First we will code this counter with a simple state initializing. Then we will code it with a lazy state initializing (I mean with the init function as third argument).

Let’s go coding the counter!

Review – How to create a counter with the useState hook?

The code to create a counter with the React useState hook

Do you remember the steps and the final code of the Simple Counter we created with the useState hook in a previous episode ? Find it below.

Initialize the state of a React counter via a value passed to useState:

import{ useState } from ‘react’;
function Counter() {
    const [count, updateCount] = useState(0);
    const increment = () => {
        updateCount(count => count + 1);
    };
    const decrement = () => {
        updateCount(count => count – 1);
    };
    const reset = () => {
        updateCount(0)
    }
    return (
      <div>
        <button
          id=”decrement”
          className=”decrement”
          onClick={decrement}>
          –
        </button>
        <button
          id=”increment”
          className=”increment”
          onClick={increment}>
          +
        </button>
        <button
          id=”reset”
          className=”reset”
          onClick={reset}>
          Reset
        </button>
        <p> Count : {count}</p>
    </div>
    )
  }

ReactDOM.render(<Counter />, document.getElementById(‘counter’));

Play with the Counter created with the react useState hook in the below pen

See the Pen
React tricks: write a simple counter with the hook useState
by Coding-Tricks (@coding-tricks)
on CodePen.

Initialize the state of a React counter via a initialState constant:

You could declare a constant named initialState, at the top of the function before the useState hook, and give it 0 as value. Then you would pass this constant as argument to useState() and to the updateCount function in the reset function instead of 0. This way would have to modify the value in one place only, in the constant initialState, in case you have to…

function Counter() {
    const initialState= 0;
    const [count, updateCount] = useState(initialState);
    const increment = () => {
        updateCount(count => count + 1);
    };
    const decrement = () => {
        updateCount(count => count – 1);
    };
    const reset = () => {
        updateCount(initialState)
    }
    return (
      // code…
    )
  }

Initialize the state of a React counter via a initialState props:

The initial state is passed as props to the component instead of being declared in a constant or a value.

The value is given when calling the component inside its parent’s component. This way different counters may be used in the same app and initialize with different values.

function Counter( {initialState} ) {
    const [count, updateCount] = useState(initialState);
    const increment = () => {
        updateCount(count => count + 1);
    };
    const decrement = () => {
        updateCount(count => count – 1);
    };
    const reset = () => {
        updateCount(initialState)
    }
    return (
      // code…
    )
  }
function App() {
    return (
        <div>
            <Counter initialState={0} />
        </div>
    )
}
ReactDOM.render(<App />, document.getElementById(‘counter’));

Play with the three Counters created with the react useState hook in the below pen. Note that the initial state received as props is either 0, or 100 or 1000. Insert three counters with different initial values in the same place in a App could be a little bit strange. Take this pen as an example of possibility only!

See the Pen
React tricks: write a simple counter with useState and initialState props
by Coding-Tricks (@coding-tricks)
on CodePen.

Remark: We could also think of passing increment and decrement values as props to give more possibilities… In that case, these values would be passed as argument to the increment and decrement functions and to the buttons displayed text.

Create a React useReducer counter

In the previous article, we have studied thoroughly the code structure when using the React useReducer hook. We will follow the main steps which are:

Now that we have understood which are all the different parts of the coding structure and how they interact, we can create a Counter.

Create a React useReducer Counter with a simple state initializing

Start coding the counter with a simple inializing before coding it in a little bit more complex way with the lazy initiaizing.

The steps to create a react useReducer Counter with simple state initializing

  1. Install React locally or create a new pen on codepen.
  2. Create the HTML element onto render the component. Give it the id “counter”.
  3. Import the useReducer hook at the beginning of the javascript file import { useState } from 'react';. Remark: when using codepen the import is not allowed, write const { useState } = React; instead.
  4. Create a functional component named Counter.
  5. Call the useReducer() hook and pass it a reducer function and an initialState constant as arguments.
  6. Declare the initialState constant above the functional component (outside the component) and initialize the state with the state property name count and giving it 0 as initial value.
  7. Between the initialState constant and the functional component, declare the reducer function and pass it state and action as arguments.
  8. Inside the reducer function, insert a switch and pass it the action type action.type as argument.
  9. In the switch, write the different cases which are ‘increment’, “decrement’ and ‘reset’. Do not forget the ‘default’.
    • The increment case will return the count state property with adding 1 to the current count state.
    • The decrement case will return the count state property with retrieving 1 to the current count state.
    • The reset case will return the initialState.
    • The default will throw a new Error().
  10. In the return() of the Counter component, insert the three buttons elements and a paragraph. Do not forget to give them an id, className and an onClick() attributes.
  11. In every button element, assign a function to the onClick attribute. This function will dispatch the action type via dispatch({type: 'typeName'}): the typeName will have to match the action type declare in the switch in the reducer function which are ‘increment’, ‘decrement’ and ‘reset’.
  12. In the paragraph, write Count: and call the count state property via {state.count}.

That’s all! Check that the counter display 0 at the first render and that the value is updated every time you click on a button. Find the full final code below. Play with it in a pen below.

The final code of a React useReducer Counter with simple state initializing

import{ useReducer } from’react’;
const initialState = {count: 0};
function reducer(state, action) {
    switch (action.type) {
        case ‘increment’:
            return {count: state.count + 1};
        case ‘decrement’:
        return {count: state.count – 1};
        case ‘reset’:
        return initialState;
        default:
        throw new Error();
    }
}
function Counter() {
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <div>
            <button
                id=”decrement”
                className=”decrement”
                onClick={() => dispatch({type: ‘decrement’})}>
                –
            </button>
            <button
                id=”increment”
                className=”increment”
                onClick={() => dispatch({type: ‘increment’})}>
                +
            </button>
            <button
                id=”reset”
                className=”reset”
                onClick={() => dispatch({type: ‘reset’})}>
                Reset
            </button>
            <p> Count : {state.count}</p>
        </div>
    )
}
ReactDOM.render(<Counter />, document.getElementById(‘counter’));

Play with the React useReducer Counter with simple state initializing in the below pen

See the Pen
React tricks: write a simple counter with the hook useState
by Coding-Tricks (@coding-tricks)
on CodePen.

Create a React useReducer Counter with a lazy state initializing

We have just coded the counter with a simple inializing. Let’s start coding it in a little bit more complex way with the lazy initializing.

As you remark, the steps are almost the same, except the fact that we create a wrapper component named App to pass the Counter component the initial state as props. The differences are written in a dark orange color.

The steps to create a react useReducer Counter with lazy state initializing

  1. Install React locally or create a new pen on codepen.
  2. Create the HTML element onto render the component. Give it the id “counter”.
  3. Import the useReducer hook at the beginning of the javascript file import { useState } from 'react';. Remark: when using codepen the import is not allowed, write const { useState } = React; instead.
  4. Create a functional component named App which will replace the Counter Component in the ReactDom.render() method.
  5. Create a functional component named Counter and pass it initialState as props.
  6. Inside the Counter component, call the useReducer() hook and pass it a reducer function, the initialState received as props and the init function as arguments.
  7. Declare the init function above the functional component (outside the component) and pass it initalState as argument. This function will initialize the state with the state property name count and  initialState as initial value.
  8. Between the initialState constant and the functional component, declare the reducer function and pass it state and action as arguments.
  9. Inside the reducer function, insert a switch and pass it the action type action.type as argument.
  10. In the switch, write the different cases which are ‘increment’, “decrement’ and ‘reset’. Do not forget the ‘default’.
    • The increment case will return the count state property with adding 1 to the current count state.
    • The decrement case will return the count state property with retrieving 1 to the current count state.
    • The reset case will return the initialState via the init() function. As the initial value is received as props, the value will have to be re-sent via an action payload (this payload value will be the props value in the return() of the Counter component).
    • The default will throw a new Error().
  11. In the return() of the Counter component, insert the three buttons elements and a paragraph. Do not forget to give them an id, className and an onClick() attributes.
  12. In every button element, assign a function to the onClick attribute. This function will dispatch the action type via dispatch({type: 'typeName'}): the typeName will have to match the action type declare in the switch in the reducer function which are ‘increment’, ‘decrement’ and ‘reset’.
  13. Add a payload property, whose value will be the props initialState, to the dispatch method onto the reset button.
  14. In the paragraph, write Count: and call the count state property via {state.count}.
  15. In the App component, insert the Counter component as child component. Pass it 0 as value to its initialState props.

As you have noted, the reset action is re-writen with a payload due to the initial state value passed as props.

That’s all! Check that the counter display 0 at the first render and that the value is updated every time you click on a button. Find the full final code below. Play with it in a pen below.

The final code of a React useReducer Counter with lazy state initializing

import { useReducer } from ‘react’;
function init(initialState) {  return {count: initialState};}
function reducer(state, action) {
  switch (action.type) {
    case ‘increment’:
      return {count: state.count + 1};
    case ‘decrement’:
      return {count: state.count – 1};
    case ‘reset’:
      return init(action.payload);
    default:
      throw new Error();
  }
}
function Counter({initialState}) {
  const [state, dispatch] = useReducer(reducer, initialState, init);
  return (
    <div>
      <button
        id=”decrement”
        className=”decrement”
        onClick={() => dispatch({type: ‘decrement’})}>
        –
      </button>
      <button
        id=”increment”
        className=”increment”
        onClick={() => dispatch({type: ‘increment’})}>
        +
      </button>
      <button
        id=”reset”
        className=”reset”
        onClick={() => dispatch({type: ‘reset’, payload: initialState})}>
        Reset
      </button>
      <p> Count : {state.count}</p>
  </div>
  )
}
function App() {
    return (
        <div>
            <Counter initialState={0} />
        </div>
    )
}
ReactDOM.render(<App />, document.getElementById(‘counter’));

Play with the React useReducer Counter with lazy state initializing in the below pen

See the Pen
React tricks: write a simple useReducer counter with simple state initializing
by Coding-Tricks (@coding-tricks)
on CodePen.

In conclusion

In this article we have reviewed how to code a useState Simple Counter and learnt how to code the useReducer Counter with both simple and lazy initializing.

In a next episode, we will try to understand what it the useRef hook, how and when to use it.

Haut de page