Home > other >  How to create a looping counter in javascript?
How to create a looping counter in javascript?

Time:07-06

I have two buttons, one increases the counter and one decreases. Each time the counter changes, the component is to change. I have tried to create both functions so I can click either button and loop through each available component (3 components).

The expected function is to display one component at a time and to cycle through them using the buttons.

The increase function almost works, but I don't know why. The decrease function does not work. Code Sandbox.

const increase = () => {
    if (counter < 3) {
      setCounter(  counter);
      console.log(counter);
    } else if (counter === 3) {
      setCounter(1);
      setShow1(!show1);
      console.log(counter);
    }
    if (counter === 2) {
      setShow2(!show2);
    }
    if (counter === 3) {
      setShow3(!show3);
    }
  };

  const decrease = () => {
    if (counter === 0) {
      setCounter(3);
      setShow3(!show3);
      console.log(counter);
    } else if (counter < 3) {
      setCounter(--counter);
      console.log(counter);
    }
    if (counter === 2) {
      setShow2(!show2);
    }
    if (counter === 1) {
      setShow1(!show1);
    }
  };

CodePudding user response:

you can do something like this

export default function App() {
  let [counter, setCounter] = useState(0);

  const increase = () => {
    setCounter(c => (c   1) % 3)
  };

  const decrease = () => {
    setCounter(c => (c - 1   3) % 3)
  };

  return (
    <div>
      <button onClick={() => decrease()}>Decrease</button>
      &nbsp;{counter}&nbsp;
      <button onClick={() => increase()}>Increase</button>
      {counter === 0 && <div className="red" /> }
      {counter === 1 && <div className="blue" /> }
      {counter === 2 && <div className="pink" /> }
    </div>
  );
}

or

import "./styles.css";
import { useState } from "react";

export default function App() {
  let [counter, setCounter] = useState(0);

  const components = [ <div className="red" />, <div className="blue" />, <div className="pink" />]

  const increase = () => {
    setCounter(c => (c   1) % components.length)
  };

  const decrease = () => {
    setCounter(c => (c - 1   components.length) % components.length)
  };

  return (
    <div>
      <button onClick={() => decrease()}>Decrease</button>
      &nbsp;{counter}&nbsp;
      <button onClick={() => increase()}>Increase</button>
      {components[counter]}
    </div>
  );
}

CodePudding user response:

Your counter is a state property. When updating a state property using its previous value (like incrementing/decrementing by 1), the callback argument of the state setter must be used.

This is due to the asynchronous nature of setState.
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

Also you cannot depend on the value of counter for your setShow1, as it may not be the latest value of counter.

You can use the following code:

increase = () => {
    setState((state)=>{
        let counter;
        if(state.counter < 3) {
            counter = state.counter   1;
        } else if(state.counter == 3) {
            counter = 1;
        }
        let show1 = (counter==1)? !state.show1: state.show1;
        let show2 = (counter==2)? !state.show2: state.show2;
        let show3 = (counter==3)? !state.show3: state.show3;

        return {counter, show1, show2, show3 };
    });
}

And similarly for decrease.

I don't think the show1, show2 & show3 properties are necessary though.

  • Related