Reputation: 285
I have this component that loads some data with buttons. I have a function that gets button via ID and updates state/variable to that buttons value, then loads data based on that. However since all the button IDs are the same, it only works for the first button...
I'm not sure how to set unique IDs for each button since they're generated through a map() function, and even if i did know, i'm not sure how my function would then target each button without writing a function for each one...
Edit: I've set unique IDs for buttons now, still need to solve the other problem.
return member.map((player, index) => (
<>
{" "}
<React.Fragment key={index}>
<br />{" "}
<div>
<br />
{player.map((stats) => (
<React.Fragment key={stats.player}>
<div class="flex-child">
<button id={'btn' + index} value={stats.player}>
{stats.player}
</button>
<p>{stats.role}</p>
<p>{stats.win_rate}</p>
<p>{stats.matches}</p>
<p>{stats.total_battles} Total Battles</p>
<p>{stats.score} / Points Earned</p>
</div>
</React.Fragment>
))}
</div>
<br />
</React.Fragment>
</>
));
};
export default SquadMembers;
here is index.js
import Head from "next/head";
import React, { useState } from "react";
import Teams from "../components/Teams";
import styles from "../../styles/Home.module.css";
import SquadMembers from "../components/SquadMembers";
import SquadData from "../components/SquadData";
export default function Home() {
const [teams, setTeams] = useState([]);
const [squads, setSquads] = useState([]);
const [player, setPlayer] = useState("Player Name");
const [squad, setSquad] = useState("default");
const [loading, setLoading] = useState(false);
function clicky() {
if (!document.getElementById("btn")) {
} else {
setPlayer(document.getElementById("btn").value);
loadPeople();
}
}
if (typeof window === "object") {
if (!document.getElementById("btn")) {
} else {
document.getElementById("btn").onclick = function () {
clicky();
};
}
}
function handleChange(e) {
setSquad(e.target.value);
}
const loadPeople = async () => {
setLoading(true);
const req = await fetch(`/api/player/${player}`);
const json = await req.json();
setTeams(json);
setLoading(false);
};
const loadSquad = async () => {
setLoading(true);
const req = await fetch(`/api/squad/${squad}`);
const json = await req.json();
setSquads(json);
setLoading(false);
setTeams([]);
};
return (
<div className={styles.main}>
<main className={styles.main}>
<h1>Silph Team Finder</h1>
<br />
<div>
<select value={squad} onChange={handleChange}>
<option value="default" selected disabled hidden>
Choose here
</option>
<option value="a342">Lots of options, cut them to save space</option>
</select>
<button onClick={() => loadSquad()}>Load</button>
<input
value={player}
id="player"
onChange={(e) => setPlayer(e.target.value)}
/>
<button onClick={() => loadPeople()} id="pbtn">
Load
</button>
{loading && <div className={styles.load}>LOADING</div>}
</div>
<div className={styles.teams}>
<SquadData squadz={squads} />
<Teams teams={teams} />
<div class="player-container">
<SquadMembers squadz={squads} />
</div>
</div>
</main>
</div>
);
}
Upvotes: 0
Views: 1250
Reputation: 11176
Would be much easier to have something like:
<button value={stats.player} onClick={() => handleClick(stats.player)}>
{stats.player}
</button>
...
const handleClick = (player) => {
setPlayer(player);
loadPeople();
}
In this way you don't need id
for button
. Not only but you will avoid warning on same id for multiple elements.
Then I would like to talk about loadPeople()
. If I understood correctly in this function you are using player
that would be setted by setPlayer
.
This is not a good approach. setPlayer
is async and you could take an old value of player
. Much better pass the last player
value directly to loadPeople
function. Something like:
const handleClick = (player) => {
setPlayer(player);
loadPeople(player);
}
const loadPeople = async (newPlayer) => {
setLoading(true);
const req = await fetch(`/api/player/${newPlayer}`);
const json = await req.json();
setTeams(json);
setLoading(false);
};
Upvotes: 1