Search code examples
reactjs

How do i render an array, which is inside an object literal, which is inside a main array using a map?


I have been idle on an issue for several days. I am trying to render items from an array which are inside an object literal, and the object literal is inside another array.

As evident in the code below, i wish to render the items inside "parts" array which is inside the main array titled "courses." In other words, i wish to display "name," "exercises," and "id" using a map.

The code in the App.jsx is as follows:

// 2.4: Course information step 9
// Let's extend our application to allow for an arbitrary number of courses:





import './eloquentstyles.css';



const App = () => {
  const courses = [
    {
      name: 'Half Stack application development',
      id: 1,
      parts: [
        {
          name: 'Fundamentals of React',
          exercises: 10,
          id: 1
        },
        {
          name: 'Using props to pass data',
          exercises: 7,
          id: 2
        },
        {
          name: 'State of a component',
          exercises: 14,
          id: 3
        },
        {
          name: 'Redux',
          exercises: 11,
          id: 4
        }
      ]
    }, 
    {
      name: 'Node.js',
      id: 2,
      parts: [
        {
          name: 'Routing',
          exercises: 3,
          id: 1
        },
        {
          name: 'Middlewares',
          exercises: 7,
          id: 2
        }
      ]
    }
  ]


  return (
    <div>
      <Course courses={courses} />

      

      
    </div>

    // <Course/>
    //Alternative to display Course component. Throws undefined in Console, therefore would not recommend for this exercise.


  )

  
}


//courses is an array which contains objects which contain arrays

const Course = ({courses}) => {

//courses is an array which contains/nests object literals. The object literals nest "parts" arrays.🤦🏾‍♀️

  console.log("** Display courses array **")
  console.log(courses)

  console.log("** Display parts array is undefined **")
  console.log(courses.parts)
  //above undefined

  console.log("")

  console.log("** Display courses in map format **")
  console.log(
  courses.map(individualcourse => 
  <li>
    {"Name: " + individualcourse.name}
    {"Id: " + individualcourse.id}
  </li>)
  )



  console.log("")





  const coursesmap = courses.map(individualcourse => 
     

    
     <li key={individualcourse.id}>
    <h2> {individualcourse.name} </h2>
    {/* {individualcourse.id} */}
    {/* <br/> */}
    {/* {individualcourse.parts} */}
    {/* parts is array of objects */}


    
     {JSON.stringify(individualcourse.parts)}


        <br/>



    





    


    {/* {console.log("gfghgh")}
    {console.log(courses.parts)} */}

{console.log("** Looping sub-arrays **")}
{console.log(

individualcourse.parts.forEach(nestedarray => {
  console.log(nestedarray)
  console.log("")

  console.log(" Extracting exercicses from sub-arrays")

  console.log(nestedarray.exercises)


  console.log("")
  console.log("** Looping courses array **")
  console.log(courses.forEach(eachcourse => {
    console.log("Course: " + eachcourse.name)
    console.log("Parts: " , eachcourse.parts)

  }))
  console.log("")

  console.log("yh")

  console.log(courses.flat(3));

 



}
)


)


}
    




    
    </li>

    
  )


  

  const my_arr = [ {id: 1, arr: [{subId: 1, value: 1}]}, {id: 2, arr: [{subId: 2, value: 2}]}, {id: 3, arr: [{subId: 3, value: 1}]}, ];
  //delete or comment out later

  // Figure how to map, flat, filter only exercises for total?
  const res = my_arr.flatMap(({arr}) => arr.filter(({value}) => value === 1));
  const re = courses.flatMap(({parts}) => parts.filter(({exercises}) => exercises !== null));
  console.log("** Testing flatmap on parts **")
  console.log(re);

  
  // function makeKeys(){

  //  courses.map(dictionary=>{
    
  //   markWord(dictionary)
    
  //   })


//   console.log("uu")
//   console.log(
//   <ul> 
//   {courses.parts.map((course) => ( 
//     <li key={course.id}> 
//       <h3>{course.name}</h3> 
//       <p>Email: {course.exercises}</p> 
//     </li> 
//   ))} 
// </ul> 

//   )



const partsarraytry = courses.parts?.map((displayone) => 
  
  
  //? at end of parts asks whether array exists
  <li key = {displayone.id}>

     <h5> {displayone.name} </h5>
     <h5> {displayone.exercises} </h5>

  </li>
  
      // <ul>
      //     <li> {displayone.name} </li>
      //     <li>{displayone.exercises}</li>
      // </ul>
  )



console.log("** Trying to use a map to render parts array, returning 'undefined.' **")

console.log(partsarraytry)





  return(

    <div> 
          <h1 style={{color: "deeppink"}} >Full Stack Part 2, Exercise 2.4: Course Information, step 9</h1>
          <h1 style={{color: "pink"}} >Web Development Curriculum</h1>


     <ul>
        {coursesmap}

        {partsarraytry}

       

       {/* {JSON.stringify(res)} */}

       {/* {JSON.stringify(re)} */}

   

     </ul>
     

    
     

</div>




  )
}




const Header = ({ courses }) => <h1>{courses}</h1>




const Content = ({ parts }) => 
  <>
    <Part
      part={parts[0]} 
    />
    <Part
      part={parts[1]} 
    />
    <Part
      part={parts[2]} 
    />      
  </>



const Part = ({ part }) => 
  <p>
    {part.name} {part.exercises}
  </p>


export default App


The console.logs above display several attempts. I tried using the dot notation in console.log: console.log(courses.parts), however "undefined" is returned inside the Console.


Solution

  • It seems you are dealing with a common issue - how to use React when dealing with complex data. Fortunately, React can really help you in this scenario. All you need to do is to start thinking in the React way!

    To be more specific, I will recommend an approach, which creates a component hierarchical tree, which represents the data structure and the logic behind it. With 2 levels deep (e.g. courses > parts) that shouldn't be a performance consideration and your code will have clean and easy to maintain structure. See recommended structure below:

    App.jsx (root component)
    │
    └── Courses.jsx (handles listing a collection of courses)
        │
        └── Course.jsx (renders each individual course)
            │
            └── Parts.jsx (handles listing a collection of parts)
                │
                └── Part.jsx (renders each individual part)
    

    Code Sample

    You can find the code sample here - https://stackblitz.com/edit/vitejs-vite-rbkudj?file=src%2Fcourse-data.js

    Few important moments from the sample:

    • I have added the useState hook to establish single place for state management and change detection for the application - check the const [courses, setCourses] = useState(courseData); in App.jsx
    • Passing parent level information to child components - it seems you want to know the courseName and courseId when rendering the individual part. Thus, I have added this extra data propagation from parent to child. For example check the Part.jsx - const Part = ({ name, exercises, courseId, courseName }) and how each parent course data is passed over
    • In your code you wanted to access log(courses.parts). This was not working as you need to do this for every individual course, e.g. log(courses[0].parts). In this case, this is handled by React when we say <Parts parts={course.parts} courseId={course.id} courseName={course.name} /> in the Course template, where we render a single course or course.parts in this case
    • In your example, you wanted to use map and you can always create seperate arrays, but having single state management and data source ensures a straightforward change detection. Any DOM re-renders will be focused on only the parts of the DOM that actually change and not everything. I am not saying multiple copies of the array are wrong, but the mindset is that you should do it when there's actual benefit, e.g. transforming the data for performance or enriching it with additional data.

    Here is the final result

    enter image description here

    Further Resource

    There's really good way set of resources you can read if you want to dive deeper:

    • Thinking in React - great piece of the documentation speaking on the importance of breaking down visual or data structure into a React component hierarchy
    • Avoid deeply nested state - React documentation explaining the pitfall with deep array structure (3+ levels) giving tips how to normalize the data and keep app performant and aligned with recommended practices