'Unable to run unique iterations for individual objects
I'm trying to present 25 entries (name, company, skill, etc.) on the page and am having trouble getting the unique information.
i.e. I only see the first entry over and over. I'm not sure how to reiterate new information since it's only going to be response.data.students[0].
This is what my code looks like now, where the mapping is:
export default function StudentList() {
let [loaded, setLoaded] = useState(false);
let [students, setStudent] = useState(" ");
function doInfo(response) {
console.log(response.data);
setStudent(response.data.students);
setLoaded(true);
}
if (loaded) {
return (
<div className="StudentList">
<div className="row">
<div className="col">
{students.map(function (data, index) {
return <StudentInfo data={data} key={index} />;
})}
</div>
</div>
</div>
);
} else {
let url = "https://api.hatchways.io/assessment/students";
axios.get(url).then(doInfo);
}
}
Here is the coding for the StudentInfo component for reference:
export default function StudentInfo() {
const [info, addInfo] = useState(" ");
function setInfo(response) {
addInfo({
number: response.data.students[0].id,
first: response.data.students[0].firstName,
last: response.data.students[0].lastName,
email: response.data.students[0].email,
company: response.data.students[0].company,
skill: response.data.students[0].skill,
average: response.data.students[0].grades[0],
});
}
let url = "https://api.hatchways.io/assessment/students";
axios.get(url).then(setInfo);
return (
<div className="StudentInfo">
<h1>{info.number}.</h1>
<h2>
Name: {info.first} {info.last}
</h2>
<h2>Email: {info.email}</h2>
<h2>Company: {info.company}</h2>
<h2>Skill: {info.skill}</h2>
<h2>Average: {info.average}</h2>
</div>
);
}
Can someone help me code it so it runs through all 25 entries, not just the first one?
Solution 1:[1]
Try something like this:
- set the array into the state
- useEffect(..., []) to trigger the data loading (only once).
- set key={id} on the mapped array expansion (or react complains for good reasons that don't apply in this particular case).
function StudentList() {
const [students, setStudents] = useState(null);
useEffect(() => {
const url = "https://api.hatchways.io/assessment/students";
axios.get(url).then(({ data: { students } }) => setStudents(students));
}, []);
if (!students) {
return ( <div>loading...</div> );
}
return (
<div className="StudentList">
<div className="row">
<div className="col">
{ students.map(student => ( <StudentInfo key={student.id} info={student} /> )) }
</div>
</div>
</div>
);
}
and StudentInfo doesn't need to reload anything, just format the data that was already fetched
export default function StudentInfo({ info }) { // edit: previous had { props: { info } } here, oops
return (
<div className="StudentInfo">
<h1>{info.number}.</h1>
<h2>
Name: {info.first} {info.last}
</h2>
<h2>Email: {info.email}</h2>
<h2>Company: {info.company}</h2>
<h2>Skill: {info.skill}</h2>
<h2>Average: {info.average}</h2>
</div>
);
}
Solution 2:[2]
Your Child component (StudentInfo) is not consuming the data passed by your parent component. Instead of calling the API for students' info again, use the prop.
export default function StudentInfo({ data }) {
const info = {
number: data.id,
first: data.firstName,
last: data.lastName,
email: data.email,
company: data.company,
skill: data.skill,
average: data.grades[0]
};
return (
<div className="StudentInfo">
<h1>{info.number}.</h1>
<h2>
Name: {info.first} {info.last}
</h2>
<h2>Email: {info.email}</h2>
<h2>Company: {info.company}</h2>
<h2>Skill: {info.skill}</h2>
<h2>Average: {info.average}</h2>
</div>
);
}
Solution 3:[3]
Issue
I only see the first entry over and over. I'm not sure how to reiterate new information since it's only going to be
response.data.students[0]
This is because the child component StudentInfo is re-requesting the students data and only accessing the 0th element for each mapped student.
export default function StudentInfo() {
const [info, addInfo] = useState(" ");
function setInfo(response) {
addInfo({
number: response.data.students[0].id, // <-- (2) update state to first student!
first: response.data.students[0].firstName,
last: response.data.students[0].lastName,
email: response.data.students[0].email,
company: response.data.students[0].company,
skill: response.data.students[0].skill,
average: response.data.students[0].grades[0],
});
}
let url = "https://api.hatchways.io/assessment/students";
axios.get(url).then(setInfo); // <-- (1) fetch all students!
return (
<div className="StudentInfo">
<h1>{info.number}.</h1>
<h2>
Name: {info.first} {info.last}
</h2>
<h2>Email: {info.email}</h2>
<h2>Company: {info.company}</h2>
<h2>Skill: {info.skill}</h2>
<h2>Average: {info.average}</h2>
</div>
);
}
Solution
You only need to request the student assessments once in the parent component, and pass down as a prop the relevant data.
Example:
function StudentList() {
const [loaded, setLoaded] = useState(false);
const [students, setStudent] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(url);
console.log(response.data);
setStudent(response.data.students);
} catch (error) {
console.error(error);
} finally {
setLoaded(true);
}
};
fetchData();
}, []);
return loaded ? (
<div className="StudentList">
<div className="row">
<div className="col">
{students.map(function (data) {
return <StudentInfo data={data} key={data.id} />;
})}
</div>
</div>
</div>
) : (
"Fetching Student Assessments."
);
}
...
function StudentInfo({ data }) {
const name = [data.firstName, data.lastName].join(" ");
const average = (
data.grades.reduce((total, grade) => total + Number(grade), 0) /
data.grades.length
).toFixed(2);
return (
<div className="StudentInfo">
<h1>{data.id}.</h1>
<h2>Name: {name}</h2>
<h2>Email: {data.email}</h2>
<h2>Company: {data.company}</h2>
<h2>Skill: {data.skill}</h2>
<h2>Average: {average}</h2>
</div>
);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | A M Akankshit |
| Solution 3 | Drew Reese |
