Home > Software design >  increment/decrement button issue in react app
increment/decrement button issue in react app

Time:03-09

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>
</>
)
}

CodePudding user response:

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>
</>
)
}

CodePudding user response:

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>

CodePudding user response:

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>
  );
}

  • Related