How to loop over objects inside jsx to print data from a multidimensional object

| In Articles | 29th March 2020

Going over all the elements of an object, in JSX is quite different than you have been used to do in JS. JSX is a mixt between html and JS and doing loops inside it is not the same and you will find being hard to make it work especially if you want to print data from a multidimensional array or object.

Multidimensional data - looping example in JSX

You can of course do the loop before the return() and save an output html in an array, then print the array where you want to do it inside the jsx from return(). And this is probably the best way to do it. But what if your object it has child objects, and this child objects has some other child objects? By using the above method, outside the return(), like in the bellow code, will make everything hard to read and understand, plus the code can get very messy.


var output = [];
for (var key in obj) {
    output.push(<div key={key} />{obj[key]}</div>);
}
return(
    <div>{output}</div>
);

While working with React on a large project, the State of the project was getting very deep and I was locking for ways to print an activity log data, row after row as it was happening. This data is saved as a JSON in the database when an user is doing a change with success. My object is on 5 levels of data and doing a loop outside the return() method was complicating things even more. The think I mostly don't like when the loop is above return is that the code is less readable. Especially if is a deep level object.. So I had to find a way to make a loop to work inside an another loop and so on as per hierarchy of the main object elements.

Example of a multidimensional loop inside return()

<div className="activity">
	<div className="logs">
		{this.state.activityLogs.map((activityLog, index) => { 
		  let logData = JSON.parse(activityLog.data);
		  return(
			<div className="child-level-1">
			  {
				Object.keys(logData).map(( val, key ) => {
					let parentData = logData[val];

					if(parentData != null){

					  //first level as object
					  if(typeof parentData == 'object'){

						return(
							<div key={'level1-'+key} className="fieldItem level1 objectItem">
								<div className="fieldName">{val}</div>
								<div className="fieldValues">
								{
								  parentData && Object.keys(parentData).map(( value, childKey ) => {
									let childData = parentData[value];									
									
									//second level as object
									if(typeof childData == 'object'){
										let dataToReturn= null;
										
										if(childData){
											dataToReturn = Object.keys(childData).map(( childChildValue, childChildKey ) => {
												let childChildData = childData[childChildValue];
												
												//third level as object
												if(typeof childChildData == 'object'){
													return(
														<div key={'level3-object-'+childChildKey} className="fieldItem level3 level3-object objectItem">
															<div className="fieldName">{childChildValue}</div>
															<div className="fieldValues">
																{
																	childChildData && Object.keys(childChildData).map(( childChildChildValue, childChildChildKey ) => {
																	let childChildChildData = childChildData[childChildChildValue];
																	
																		if(typeof childChildChildData == 'object'){
																			return(
																				<div key={'level4-object-'+childChildChildKey} className="fieldItem level4 level4-object objectItem">
																					<div className="fieldName">{childChildChildValue}</div>
																					<div className="fieldValues">
																						{
																							childChildChildData && Object.keys(childChildChildData).map(( childChildChildChildValue, childChildChildChildKey ) => {
																							let childChildChildChildData = childChildChildData[childChildChildChildValue];
																								if(typeof childChildChildChildData == 'object'){
																									return(
																										<div key={'level5-object-'+childChildChildChildKey} className="fieldItem level5 level5-object objectItem">
																											<div className="fieldName">{childChildChildChildValue}</div>
																											<div className="fieldValues">
																												{JSON.stringify(childChildChildChildData)}
																											</div>
																										</div>
																									)
																								}else{
																									return(
																										<div key={'level5-'+childChildChildChildKey} className="fieldItem level5"><div className="fieldName">{childChildChildChildValue}</div><div className="fieldValue">{childChildChildChildData}</div></div>
																									)
																								}
																							})
																						}
																					</div>
																				</div>
																			)
																		}else{
																			return(
																				<div key={'level4-'+childChildChildKey} className="fieldItem level4"><div className="fieldName">{childChildChildValue}</div><div className="fieldValue">{childChildChildData}</div></div>
																			)
																		}
																	})
																}
															</div>
														</div>
													)
												}else{
																				
													//third level
													return(
														<div key={'level3-'+childChildKey} className="fieldItem level3"><div className="fieldName">{childChildValue}</div><div className="fieldValue">{childChildData}</div></div>
													)
												}
											});
										}
										if(val == 'details'){
											return(
												<div key={'level2-object-'+childKey} className="fieldItem level2 level2-object objectItem">
													<div className="fieldName">{val}</div>
													<div className="fieldValues">
														{dataToReturn}
													</div>
												</div>
											)
										}else{
											return(
												<div key={'level2-object-'+childKey} className="fieldItem level2 level2-object">
													{dataToReturn}
												</div>
											)
										}
										
									}else{
										return(
											<div key={'level2-'+childKey} className="fieldItem level2"><div className="fieldName">{value}</div><div className="fieldValue">{childData}</div></div>
										)
									}
									
								  })
								}
								</div>
							</div>
						)

					  }else{
						//first level as string or number
						return(
						  <div key={'level1-'+key} className="fieldItem level1"><div className="fieldName">{val}</div><div className="fieldValue">{parentData}</div></div>
						)
					  }


					}else{
					  //first level as null
					  return(
						<div key={'level1-'+key} className="fieldItem level1"><div className="fieldName">{val}</div><div className="fieldValue">null</div></div>
					  )
					}

				  }
				)
			  }
			</div>
			)
		  })
		}
	</div>
  </div>

And the JSON data send from the backend using an API request is looking like this

{
   "data": [
      {
         "id": 1,
         "message": "Test",
         "data": {
            "id": 12,
            "license": 1,
            "created_at": "2020-03-12 11:48:40",
            "updated_at": "2020-03-26 10:15:43",
            "details": {
               "el_id": 12,
               "name": "Test",
               "code": "Code123",
               "created_at": "2020-03-12 11:48:40",
               "updated_at": "2020-03-24 16:09:58"
            },
            "aChildObject": {
               "1": {
                  "value": "1",
                  "el_id": 12,
                  "product_id": 1
               },
               "2": {
                  "value": "1",
                  "el_id": 12,
                  "product_id": 2
               },
               "3": {
                  "value": "1",
                  "el_id": 12,
                  "product_id": 3
               },
            },
            "aNewObject": {
               "id": 223,
               "el_id": 12,
               "name": "Test",
               "created_at": "2020-03-12 11:48:40",
               "updated_at": "2020-03-26 10:15:43"
            },
            "anAnotherObject": [
               {
                  "id": 34,
                  "el_id": 23,
                  "active": 1,
                  "name": "John",
                  "surname": "Doe",
                  "phonenumber": null,
                  "mobile": null,
                  "created_at": "2020-03-12 11:48:40",
                  "updated_at": "2020-03-23 12:38:35",
                  "email": "test@gmail.com",
                  "emails": [
                     {
                        "id": 211,
                        "contact_id": 34,
                        "email": "test@gmail.com",
                        "created_at": "2020-03-12 11:48:40",
                        "updated_at": "2020-03-12 11:49:05"
                     }
                  ]
               }
            ]
         },
         "date": "2020-03-26 10:15:45"
      }
   ]
}

As you can see the JS is looping over each child of an object and checking if is an object or not, like a number of string. If is an object, is converting the object into an array with Object.keys and looping over it with map(). Inside map() I used an arrow function which let me define variables inside and do a new loop over a new child object, and so on.