skip to Main Content

To be honest I am not even 100% that this is my problem – it could simply be that I have the structure wrong. But this is what I am trying to do:

Team :
{
    1 : {
            name: "Joe",
            items: ['hat', 'gloves']
        },
    2 : {
            name: "Kate",
            items: ['bonnet']
        }
}

const [team, setTeam] = useState(Team);

There could be any number of people in the team. There could be any number of items in the items collection.

I know the number of the person e.g. 1 for Jim and I know the index of the items array I want to change and the new value.

This is a simplified example but it is exactly the problem.

So, let’s say I want to replace Joe’s gloves with mittens:

function update(teamNumber, itemNumber, newItem) {

    let newItems = Team[teamNumber].items.map( (val, idx) => {
            if (idx == itemNumber) 
            {
                return newItem;
            }
            else
            {
                return val;
            }
    });

    setTeam(

         (prevState) => { 
                return {...prevState,
                    teamNumber : {
                    ...prevState[teamNumber],
                    items : newItems
                }
            };

        }
    )

}

There are two separate problems:

  1. How to update the specific index element in the array. I have not even tried to do that in the state setter – I try to do it separately in the map routine.

  2. There seems to be a problem using a variable, teamNumber as a key in the state setter. At least when I run with this code it appears to wipe state (at least nothing is displayed in the bound input field) but if I use a specific number e.g. 1 for teamNumber then it appears to work.

I could live with 1. But 2. is a blocker. (My workaround is to do a clean unlinked copy of the whole object – there are more fields – and replace it completely).

Another approach might be to "flatten the state" – i can see that; but, again, I can’t create a set variable for each team member because they are variable..

Thank you

2

Answers


  1. I would just reset the state like this. It is a little verbose but should do the job. Let me know if you need me to explain this in more depth:

    setState(prev => {
      ...prev, 
      teamNumber: {
        ...prev[teamNumber],
        items: [...prev[teamNumber].items.slice(0, itemNumber), newItem, 
          ...prev[teamNumber].items.slice(itemNumber + 1, 
          prev[teamNumber].items.length)]
      }
    })
    
    Login or Signup to reply.
  2. wrap your key in bracket to make it dynamic as Unmitigated mention:

    function update(teamNumber, itemNumber, newItem) {
      let newItems = team[teamNumber].items.map((val, idx) => {
        if (idx === itemNumber) {  // use === for a strict equality
          return newItem;
        } else {
          return val;
        }
      });
    
      setTeam((prevState) => ({
        ...prevState,
        [teamNumber]: {
          ...prevState[teamNumber],
          items: newItems,
        },
      }));
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search