Java Gamer
Java Gamer

Reputation: 577

React - on OnClick display next element in array

I have a variable called assignee. Assignee can be one of the three names I listed below in the array. On startup I call a API that returns the current assignee (if an assignee exists). I set the assignee variable to the name I received from the API.

I have a div element that displays the assignee name, when a user clicks this element I want the assignee to change according to the list order. How do I solve this?

Lets say I get Sara from the Api, now when I click the element I want assignee to change to Bill then to Steve, then to Sara. It should go back to the start of the array and re-iterate. Is this the best approach to this problem or are there better ways to solve this?

const users = ["Bill", "Steve", "Sara"];
const [assignee, setAssignee] = useState<string>();

..

const handleAssigneeOnClick = () => {
    setAssignee(users[0]);
  };

..

<div
  className="assignee"
  onClick={() => {
    handleAssigneeOnClick();
  }}
>
  <p>{assignee}</p>
</div>

Upvotes: 0

Views: 3825

Answers (2)

Chris
Chris

Reputation: 59511

You could alter the assignee state variable to instead hold the index for the corresponding person in the array. Like this:

const [assignee, setAssignee] = useState<number>(-1);

const handleAssigneeOnClick = () => {
  setAssignee(prev => (prev + 1) % 3);
};

This sets the index to be the remainder of the division of the index + 1 by 3. You could also do users.length for something more dynamic, should your array grow.

And then in your return, display the name like this:

<div
  className="assignee"
  onClick={handleAssigneeOnClick}
>
  <p>{users[assignee]}</p>
</div>

I set the initial state value to -1 because you seem to have had the initial string empty until click. You can change this obviously to 0 if you want someone assigned by default.


Working example:

const users = ["Bill", "Steve", "Sara"];

const App = () => {
  const [assignee, setAssignee] = React.useState(-1);
  
  const handleAssigneeOnClick = () => {
    setAssignee(prev => (prev + 1) % 3);
  };
   
  return (
    <div
      className="assignee"
      onClick={handleAssigneeOnClick}
    >
      <p>{users[assignee]}</p>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('app'));
div {
  background: red;
  height: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 1

Brian Thompson
Brian Thompson

Reputation: 14365

I would structure it a little differently and store the index in state.

It checks to see if the current index is the last one, and moves back to the beginning if so. Otherwise, it just adds one.

Then you use the index to print the current selected user.

const {useState, useEffect} = React;

const users = ["Bill", "Steve", "Sara"];
const Example = () => {
  const [selected, setSelected] = useState(0);
  
  const handleAssigneeOnClick = () => {
    setSelected(prev => {
      if (prev === users.length - 1) {
        return 0;
      } else {
        return prev + 1;
      }
    });
  };
   
  return (
    <div onClick={handleAssigneeOnClick}>
      <p>{users[selected]}</p>
    </div>
  )
}

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

Upvotes: 1

Related Questions