'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>
  );
}

Edit unable-to-run-unique-iterations-for-individual-objects

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