Prince
Prince

Reputation: 15

increment/decrement button issue in react app

Actually i want to show this Names in a sequence but whenever i click increment button the order ( in useState ) increment by 1 but when i click decrement button first time the order again increment by 1 and then is less than one.

function func() {
  let [getVal, setVal] = useState({
    alerts: "no alerts",
    order: 0,
  });
  
  let Names = [
      "Default",
      "Evil laugh",
      "classic alarm",
      "Pause",
      "intro music",
      "Got item",
      "Old bounce",
      "bark",
      "alarm tone",
    ];

  function slider(e) {
    let { order } = getVal,
    value = e.target.id,
    total = Names.length; 
    if (value === "up" && order !== total - 1) {
      setVal((rest) => ({ ...rest, order:order + 1 })); 
    } else if (value === "down" && order !== 0) {
      setVal((rest) => ({ ...rest, order: order - 1 })); 
    }
    setVal((rest) => ({ ...rest, alerts: Names[order] }));
  }


  return (
    <>
       
        <button
          onClick={slider}
          id="up"
        >
          up
        </button>

        <p>
          {getVal.alerts}
        </p>

        <button
          onClick={slider}
          id="down"
        >down
        </button>
</>
)
}

Upvotes: 0

Views: 205

Answers (3)

Silvan Bregy
Silvan Bregy

Reputation: 2734

Here is a simplified version of yor approach.


function func() {
  let [order, setOrder] = useState(0);

  let Names = [
    "Default",
    "Evil laugh",
    "classic alarm",
    "Pause",
    "intro music",
    "Got item",
    "Old bounce",
    "bark",
    "alarm tone"
  ];

  function slider(e) {
    var action = e.target.id,
        total = Names.length;

    if (action === "up" && order !== total - 1) {
      setOrder( order + 1 );
    } else if (action === "down" && order !== 0) {
      setOrder( order - 1 );
    }
  }

  return (
    <div>
      <button onClick={slider} id="up">
        up
      </button>

      <p>{Names[order]}</p>

      <button onClick={slider} id="down">
        down
      </button>
    </div>
  );
}

Upvotes: 0

Andy
Andy

Reputation: 63524

Your handler doesn't need to be that complicated. I'd also recommend using data-attributes instead of ids. I've made a couple of changes:

  1. To variable names so they make a little more sense - when you're talking about arrays index is better than order.

  2. There's no longer a need to have an alert in state. Just load the names into state, and then have the component display the name at the current index.

const { Fragment, useEffect, useState } = React;

// Pass in the names as a prop
function Example({ names }) {

  // Add the names to state, and initialise the index
  const [ state, setState ] = useState({ names, index: 0 });

  function handleClick(e) {
    
    // Get the id from the button's dataset
    const { id } = e.target.dataset;

    // Get the names, and index, from state
    const { names, index } = state;

    // Create a new index
    const newIndex = id === 'down'
      ? index - 1
      : index + 1;

    // Set a new state if the newIndex is between 0
    // and less than the names array length
    if (newIndex >= 0 && newIndex < names.length) {
      setState({ ...state, index: newIndex });
    }
  
  }

  return (
    <Fragment>
      <button data-id="down" onClick={handleClick}>Down</button>
      <p>{state.names[state.index]}</p>
      <button data-id="up" onClick={handleClick}>Up</button>
    </Fragment>
  );
};

const names=["Default","Evil laugh","classic alarm","Pause","intro music","Got item","Old bounce","bark","alarm tone"];

ReactDOM.render(
  <Example names={names} />,
  document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 1

Ankit Saxena
Ankit Saxena

Reputation: 1197

You need to make the following change in your slider() function. It will fix your issue.

Updating state in react is an asynchronous task. You were doing it both inside and outside the if condition. That's why it was not decrementing the order on first down click.

  function slider(e) {
    let { order } = getVal,
    value = e.target.id,
    total = Names.length; 

    if (value === "up" && order !== total - 1) {
      setVal((rest) => ({ ...rest, order:order + 1, alerts: Names[order + 1]})); 
    } else if (value === "down" && order !== 0) {
      setVal((rest) => ({ ...rest, order: order - 1, alerts: Names[order - 1] })); 
    }
  }

Full React Code Snippet:

import React, { useState } from "react";

function func() {
  let [getVal, setVal] = useState({
    alerts: "no alerts",
    order: 0,
  });
  
  let Names = [
      "Default",
      "Evil laugh",
      "classic alarm",
      "Pause",
      "intro music",
      "Got item",
      "Old bounce",
      "bark",
      "alarm tone",
    ];

  function slider(e) {
    let { order } = getVal,
    value = e.target.id,
    total = Names.length; 

    if (value === "up" && order !== total - 1) {
      setVal((rest) => ({ ...rest, order:order + 1, alerts: Names[order + 1]})); 
    } else if (value === "down" && order !== 0) {
      setVal((rest) => ({ ...rest, order: order - 1, alerts: Names[order - 1] })); 
    }
  }


  return (
    <>
       
        <button
          onClick={slider}
          id="up"
        >
          up
        </button>

        <p>
          {getVal.alerts}
        </p>

        <button
          onClick={slider}
          id="down"
        >down
        </button>
</>
)
}

Upvotes: 1

Related Questions