Skip to content
Advertisement

Setting state of nested array with React Hooks

I have been working with React Hooks for a while, but the biggest problem for me is working with arrays.

I am making a register form for teams. Teams have players (array of strings).

The user should be able to add a team, and for each team, an input is shown with the current members in the team displayed above the input.

My question: How do I set the state of a nested array with React Hooks?

On the button click, it should (for now) add a string to the players array of the current team.

My Code:

interface ITeam {
    id: string;
    players: Array<string>;
}


export default function Team() {
const [teams, setTeams] = useState<Array<ITeam>>([{id: '1', players: ['a', 'b']}]);

return (
    <div>
        {teams.map((team, teamIndex) => {
            return (
                <div key={teamIndex}>
                    <h2>Team {teamIndex + 1}</h2>
                    <ul>
                        {team.players.map((player, playerIndex) => {
                            return (
                                <div key={playerIndex}>
                                    {player}
                                </div>
                            );
                        })}
                    </ul>
                    <button onClick={() => setTeams([...teams, team.players.concat('c')])}>Add player</button>
                </div>
            );
        })}
    </div>
);
}

Advertisement

Answer

You need to make use of team index and update that particular teams value using spread syntax and slice like

  function addPlayer(index) {
    setTeams(prevTeams => {
      return [ ...prevTeams.slice(0, index), {...prevTeams[index], players: [...prevTeams[index].players, "c"] }, ...prevTeams.slice(index+1)];
    });
  }

or better you can just use map to update

function addPlayer(index) {
  setTeams(prevTeams => {
    return prevTeam.map((team, idx) => {
      if(index === idx) {
        return {...prevTeams[index], players: [...prevTeams[index].players, "c"]}
      } else {
        return team;
      }
    })
  });
}

const { useState } = React;

function Team() {
  const [teams, setTeams] = useState([{ id: "1", players: ["a", "b"] }]);

  function addPlayer(index) {
    setTeams(prevTeams => {
      return [ ...prevTeams.slice(0, index), {...prevTeams[index], players: [...prevTeams[index].players, "c"] }, ...prevTeams.slice(index+1)];
    });
  }

  return (
    <div>
      {teams.map((team, teamIndex) => {
        return (
          <div key={teamIndex}>
            <h2>Team {teamIndex + 1}</h2>
            <ul>
              {team.players.map((player, playerIndex) => {
                return <div key={playerIndex}>{player}</div>;
              })}
            </ul>
            <button onClick={() => addPlayer(teamIndex)}>Add player</button>
          </div>
        );
      })}
    </div>
  );
}

ReactDOM.render(<Team />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
Advertisement