What I’m trying to do is pull a name of a football player from an NFL API then use that name as a link to their page. For this error it’s combining all the links into one link which is very weird because when I was just testing all my routes without the api it worked and did not do this. It’s outputting something like this TaaotaTarlaoaortaJoshAllen to the page instead of just each player’s name then a space and another player’s name. It should be like (Bold means link):
Tua Tagovailoa Patrick Mahomes Joe Burrow Josh Allen
Side note: I feel like it’s definitely pulling data from the api just not how I want to. It’s sorta making out the names that are pulled from the api just all as one link but I want multiple links.
This is how it worked without the API and outputted like shown below:
Special Team 1 Special Team 2 Special Team 3 Special Team 4
import { Link } from "react-router-dom"
import _navbar from "../NavBar/navbar";
export default function _specialTeamsPage() {
const specialteams = [1, 2, 3, 4, 5];
return (
<>
<_navbar />
<div>
{specialteams.map((specialteam) => (
<Link key={specialteam} to={`/specialteam/${specialteam}`}>
Special Team {specialteam}
</Link>
))}
</div>
</>
);
}
This is the code block with the API that is not working:
import { Link } from "react-router-dom";
import _navbar from "../NavBar/navbar";
import React, { useEffect, useState } from "react";
import styles from './card.module.css';
export default function _quarterbacksPage() {
const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417];
const [names, setNames] = useState([]);
for (let i = 0; i < quarterbacks.length; i++){
const options = {
method: 'GET',
headers: {
'x-rapidapi-key': 'secret key',
'x-rapidapi-host': 'nfl-api-data.p.rapidapi.com'
}
};
const FullNameUrl = 'https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=' + quarterbacks[i];
const fetchFullName = async () => {
fetch(FullNameUrl, options)
.then(response => response.json())
.then(response => {
const name = response.athlete.fullName;
setNames([...names, ...name]);
})
};
useEffect(() => {
fetchFullName();
}, []);
}
return (
<>
<div>
<_navbar />
{names.map((name) => (
<Link key={name} to={`/quarterback/${name}`}>
{name}
</Link>
))}
</div>
</>
);
}
There are several problems here
- Don’t call
useEffect()
in a loop - When setting state based on the current value, use the functional version of the setter
- Using spread syntax on a string breaks it down to an array of characters
- What happens if players have the same name? You shouldn’t use it as the
key
prop when theid
is much more suitable
What you should do instead is perform all your fetch calls as one asynchronous operation and then set the entire state.
For example
// these functions can be defined outside your component
const fetchFullName = async (id) => {
const res = await fetch(
`https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=${encodeURIComponent(id)}`,
{
headers: {
"x-rapidapi-key": "secret key",
"x-rapidapi-host": "nfl-api-data.p.rapidapi.com",
},
},
);
if (!res.ok) {
throw new Error(`Name lookup for id '${id}' failed`);
}
return (await res.json()).athlete.fullName;
};
// returns an array of {id, name} objects
const fetchFullNames = async (ids) =>
Promise.all(ids.map(async (id) => ({ id, name: await fetchFullName(id) })));
// is this meant to be a static value?
const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417];
export default function _quarterbacksPage() {
const [names, setNames] = useState([]);
useEffect(() => {
fetchFullNames(quarterbacks).then(setNames).catch(console.error);
}, []);
return (
<div>
<_navbar />
{names.map(({ id, name }) => (
<Link key={id} to={`/quarterback/${id}`}>
{name}
</Link>
))}
</div>
);
}
2