Home > Enterprise >  How can I increment/decrement separate counters in React?
How can I increment/decrement separate counters in React?

Time:12-09

I made a ticket order system for a project, however when I want to increment the amount of one of the tickets both of the counters increase. I am not sure why this happens, but I assume it is because only one value is stored in state.

export default function Ticket() {

    const [count, setState] = useState(0); // useState returns a pair. 'count' is the current state. 'setCount' is a function we can use to update the state.

    function increment(e) {
        //setCount(prevCount => prevCount =1);
        setState(function (prevCount) {
            return (prevCount  = 1);
        });
    }

    function decrement() {
        setState(function (prevCount) {
            if (prevCount > 0) {
                return (prevCount -= 1);
            } else {
                return (prevCount = 0);
            }
        });
    }


    return (
        <div>
            <section className="ticket-step">
                <h1>TICKETS</h1>
            </section>

            <div className="ticket-booking is-flexbox">

                <section className="ticket-content">

                    <ul className="tickets-tab is-flexbox">
                        <li>Tickets</li>
                        <li>Abbonementen</li>
                    </ul>


                    <div className="ticket-list-section">

                        <div className="ticket-list-details heading">
                            <div id="calender">
                                <h3>Datum : 30 - 10 - 2022</h3>
                            </div>

                            <div id="opening">
                                <h3>Openingstijden: 12:00 - 20:00 </h3>
                            </div>
                        </div>

                        <div className="ticket-list-details">

                            <div className="ticket-block">

                                <div className="ticket-title">
                                    <h3>Parkeer ticket</h3>
                                </div>
                                <div className="price">
                                    <h3>Prijs: $20</h3>
                                </div>
                                <div className="counter">
                                    <button className="increase-amount" onClick={increment}> </button>
                                    <input type="text" className="amount" defaultValue="0" value={count}/>
                                    <button className="decrease-amount" onClick={decrement}>-</button>
                                </div>

                            </div>

                            <div className="ticket-block">

                                <div className="ticket-title">
                                    <h3>Early Horror-ticket</h3>
                                </div>
                                <div className="price">
                                    <h3>Prijs : $59</h3>
                                </div>
                                <div className="counter">
                                    <button className="increase-amount" onClick={increment}> </button>
                                    <input type="text" className="amount" defaultValue="0" value={count}/>
                                    <button className="decrease-amount" onClick={decrement}>-</button>
                                </div>

                            </div>

                        </div>
                    </div>
                </section>

                <aside className="sidebar-overview">
                    <h1>besteloverzicht</h1>
                    <div className="sidebar-overview-content">

                    </div>
                    <hr/>
                    <div className="sidebar-overview-total">
                        <h3>Totaal: $0</h3>
                    </div>
                </aside>
            </div>
        </div>
    )
}

I tried to change useState and somehow store different states of the counters in an array, but that didn't work.

How can use the counters separately and store the state of the different buttons?

CodePudding user response:

I'd say create a Button component and use that instead of adding more counters... as you might want to re-use this in different pages later as well.

Button.js

import { useState } from "react";

function Button() {
  const [count, setState] = useState(0); // useState returns a pair. 'count' is the current state. 'setCount' is a function we can use to update the state.

  function increment(e) {
    //setCount(prevCount => prevCount =1);
    setState(function (prevCount) {
      return (prevCount  = 1);
    });
  }

  function decrement() {
    setState(function (prevCount) {
      if (prevCount > 0) {
        return (prevCount -= 1);
      } else {
        return (prevCount = 0);
      }
    });
  }

  return (
    <div className="counter">
      <button className="increase-amount" onClick={increment}>
         
      </button>
      <input type="text" className="amount" defaultValue="0" value={count} />
      <button className="decrease-amount" onClick={decrement}>
        -
      </button>
    </div>
  );
}

export default Button;

and just re-use it in your page;

export default function Ticket() {
    return (
        <div>
            <section className="ticket-step">
                <h1>TICKETS</h1>
            </section>

            <div className="ticket-booking is-flexbox">

                <section className="ticket-content">

                    <ul className="tickets-tab is-flexbox">
                        <li>Tickets</li>
                        <li>Abbonementen</li>
                    </ul>


                    <div className="ticket-list-section">

                        <div className="ticket-list-details heading">
                            <div id="calender">
                                <h3>Datum : 30 - 10 - 2022</h3>
                            </div>

                            <div id="opening">
                                <h3>Openingstijden: 12:00 - 20:00 </h3>
                            </div>
                        </div>

                        <div className="ticket-list-details">

                            <div className="ticket-block">

                                <div className="ticket-title">
                                    <h3>Parkeer ticket</h3>
                                </div>
                                <div className="price">
                                    <h3>Prijs: $20</h3>
                                </div>

                                <Button/>

                            </div>

                            <div className="ticket-block">

                                <div className="ticket-title">
                                    <h3>Early Horror-ticket</h3>
                                </div>
                                <div className="price">
                                    <h3>Prijs : $59</h3>
                                </div>

                                <Button/>

                            </div>

                        </div>
                    </div>
                </section>

                <aside className="sidebar-overview">
                    <h1>besteloverzicht</h1>
                    <div className="sidebar-overview-content">

                    </div>
                    <hr/>
                    <div className="sidebar-overview-total">
                        <h3>Totaal: $0</h3>
                    </div>
                </aside>
            </div>
        </div>
    )
}

CodePudding user response:

You should use 2 counters instead of just one, so you'll have 2 useState() statements.

const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);

Then your buttons and displays need to reference the separate counter states appropriately.

    <div className="counter">
      <button className="increase-amount" onClick={increment}> </button>
      <input type="text" className="amount" defaultValue="0" value={count1}/>
      <button className="decrease-amount" onClick={decrement}>-</button>
    </div>

You'll also need to have 2 separate increment functions and 2 separate decrement functions. Alternately, you can have one increment function that takes an argument to specify which counter to update.

CodePudding user response:

You could implement a counter hook as well as a counter component.

useCounter.jsx

import { useState } from "react";

// An enum to track whether it's increment or decrement

const actionEnum = {
  INCREMENT: "increment",
  DECREMENT: "decerement"
};
const useCounter = (initialValue = 0) => {

  // State to hold the value
  const [count, setCount] = useState(initialValue);

  // The function that set's the count based on the name of the element

  function handleChange({ target }) {
    const { name } = target;
    setCount((prev) => (name === actionEnum.INCREMENT ? prev   1 : prev - 1));
  }
  return {
    count,
    handleChange,
    actionEnum
  };
};

export default useCounter;

Counter.jsx

import useCounter from "./useCounter";

const Counter = () => {
  const { count, handleChange, actionEnum } = useCounter();

  return (
    <>
      <p>{count}</p>
      <button name={actionEnum.INCREMENT} onClick={handleChange}>
         
      </button>
      <button name={actionEnum.DECREMENT} onClick={handleChange}>
        -
      </button>
    </>
  );
};
export default Counter;

Then finally just import the Counter component for each counter you need.

Example : https://codesandbox.io/s/patient-hooks-0ohyun?file=/src/App.js

You can also update the component so that it takes a prop for a fn that sets a global state which tracks all the counters

CodePudding user response:

Hope this helps, see how I changed the value for the input tags and useState Let me know if it worked

import React, { useState } from "react";

export default function App() {
  const [count, setState] = useState({
    first: 0,
    second: 0
  });

  function increment(type) {
    setState(prev => ({
      ...prev,
      [type]: count[type]   1
    }))
  }

  function decrement(type) {
    if(count[type] === 0) return;
    setState(prev => ({
      ...prev,
      [type]: count[type] - 1
    }))
  }

  return (
    <div>
      <section className="ticket-step">
        <h1>TICKETS</h1>
      </section>

      <div className="ticket-booking is-flexbox">
        <section className="ticket-content">
          <ul className="tickets-tab is-flexbox">
            <li>Tickets</li>
            <li>Abbonementen</li>
          </ul>

          <div className="ticket-list-section">
            <div className="ticket-list-details heading">
              <div id="calender">
                <h3>Datum : 30 - 10 - 2022</h3>
              </div>

              <div id="opening">
                <h3>Openingstijden: 12:00 - 20:00 </h3>
              </div>
            </div>

            <div className="ticket-list-details">
              <div className="ticket-block">
                <div className="ticket-title">
                  <h3>Parkeer ticket</h3>
                </div>
                <div className="price">
                  <h3>Prijs: $20</h3>
                </div>
                <div className="counter">
                  <button className="increase-amount" onClick={() => increment("first")}>
                     
                  </button>
                  <input
                    type="text"
                    className="amount"
                    defaultValue="0"
                    value={count.first}
                  />
                  <button className="decrease-amount" onClick={() => decrement("first")}>
                    -
                  </button>
                </div>
              </div>

              <div className="ticket-block">
                <div className="ticket-title">
                  <h3>Early Horror-ticket</h3>
                </div>
                <div className="price">
                  <h3>Prijs : $59</h3>
                </div>
                <div className="counter">
                  <button className="increase-amount" onClick={() => increment("second")}>
                     
                  </button>
                  <input
                    type="text"
                    className="amount"
                    defaultValue="0"
                    value={count.second}
                  />
                  <button className="decrease-amount" onClick={() => decrement("second")}>
                    -
                  </button>
                </div>
              </div>
            </div>
          </div>
        </section>

        <aside className="sidebar-overview">
          <h1>besteloverzicht</h1>
          <div className="sidebar-overview-content"></div>
          <hr />
          <div className="sidebar-overview-total">
            <h3>Totaal: $0</h3>
          </div>
        </aside>
      </div>
    </div>
  );
}

  • Related