1

I'm trying to select an id using a onClick method, the only problem is that when i click a button only the last id is displayed.

const renderTableData = () => {
let id = 0;
return (
  <tr>
    {days.map((val) => (
      <td>
        {timeSlot.map((time, i) => {
          if (occupiedSlots().result.includes(id + 1)) {
            return (
              <button id={id++} className="disabledButton">
                {time}
              </button>
            );
          } else {
            return (
              <button id={id++} className="activeButton" onClick ={() => {canBookSlot({id})}}> 
                {time}
              </button>
            );
          }
        })}
      </td>
    ))}
  </tr>
);
};

This is what the canBookSlot() function looks like:

 const canBookSlot = (id) => {
let userDetailsString = localStorage.getItem("userDetails");
const userDetailsObj = JSON.parse(userDetailsString)

if(userDetailsObj.canBook != 0){
      Axios.post('http://localhost:3001/api/book/week1/ex', {
         room: userDetailsObj.room,
         id: id
    })

    return console.log(id) 
} else {
  return console.log("somethings wrong")
}

};

The output is always 70. how do i fix this?

2 Answers2

2

Consider your variable called days - if something else did days = null; you would expect your days.map to fail when it next renders. id is no different - every button is using the same id variable, so when you increase it, all usage of that value will witness that increase too.

So, you need to "capture" the current value of id for a given button. Due to the way how scope works in JS, a function body has its own set of variables. Because you are inside the function callback of map, that means we can define a buttonId variable inside it, and it will naturally be per button:

const renderTableData = () => {
let id = 0;
return (
  <tr>
    {days.map((val) => (
      <td>
        {timeSlot.map((time, i) => {
          var buttonId = id++;
          if (occupiedSlots().result.includes(buttonId + 1)) {
            return (
              <button id={buttonId} className="disabledButton">
                {time}
              </button>
            );
          } else {
            return (
              <button id={buttonId} className="activeButton" onClick ={() => {canBookSlot({id: buttonId})}}> 
                {time}
              </button>
            );
          }
        })}
      </td>
    ))}
  </tr>
);
};
Luke Briggs
  • 3,745
  • 1
  • 14
  • 26
0

id is a global variable, and react itself has no idea of, everytime your table renders a button:

<button id={id++}> </button>

The value of id increases by id++. And after the whole table gets rendered, the final value of id got incremented to the total length of the whole 2d array - 70. (I'm pretty sure you've disabled strickMode, otherwise the value could've doubled.)

So, that's the reason why you'll always get the last id. There're several ways to solve this, but the key is to understand why react use key prop for rendering array in the first place, for more detailed explanation, you can look up this answer.

Enfield Li
  • 1,952
  • 1
  • 8
  • 23
  • Ahh okey that makes sense, i looked at the link but I'm not able to find an answer to this problem only the importance of having a unique key. – Max Andersson Jul 09 '22 at 15:18
  • @MaxAndersson the problem you're having is unrelated to having a unique key :) – Luke Briggs Jul 09 '22 at 15:18
  • I know, i was refering to the link. I get 70 unique keys the problem is as mentioned that react only stores the final value of `id` – Max Andersson Jul 09 '22 at 15:21