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>