0

Using map in map to generate jsx content throws error

var exampleData = [
    { name: "Alex", age: 13, date: new Date()},
    { name: "Dominic", age: 313, date: new Date()},
    { name: "Fiona", age: 33, date: new Date()}
]

var tableContent = 
  <div>
    {exampleData.map((element,index) => { 
        return(
          <tr>
            <th scope="row">{index}</th> 
            {Object.keys(element).map((key)=>{ 
              return(
                <tr scope="row">{element[key]}</tr>
              )}
            }
           </tr>
        )
       })
     }
  </div>

React throws error : Objects are not valid as a React child. If you meant to render a collection of children, use an array instead

In that case, sure i could just dont use second map and write code manually, but i have dozens of different kind of data to show up with a lot of keys that can change any time in development. Any advice how to do it dynamicaly?

4
  • How and where are you using the table content Commented Jun 16, 2019 at 8:02
  • I get data from my API in Json format and then i parse table headers from first element and showed tableContent is put into tbody Commented Jun 16, 2019 at 8:06
  • from that data you want to create a table where index is table header and body is the each and every key value pair in that object rit??? Commented Jun 16, 2019 at 8:10
  • This is just table body content. Headers in table are my exampleData object keys and i didnt paste code of generating thead because it works well. Index is just for users to count table rows at first place Commented Jun 16, 2019 at 8:17

2 Answers 2

1

You are on the right track.

This is what I use:

function toString(object) {
    if (typeof object === "string") return object;
    if (typeof object === "number") return object;
    if (typeof object === "boolean") return object ? "True" : "False";
    if (object === null || object === undefined) return "N/A";
    if (typeof object === "function") return "Function";
    if (object instanceof Date) return object.toLocaleString();
    if (object.hasOwnProperty("toString")) return object.toString();
    return JSON.stringify(object);
}

function TableView(props) {
    if (props.object.length < 1) return null;

    let keys = Object.keys(props.object[0]);

    return <table>
        <thead>
            <tr>
                {keys.map((key, i) => <td key={i}>{key}</td>)}
            </tr>
        </thead>
        <tbody>
            {props.object.map((row, i) => <tr key={i}>
                {keys.map((key, i) => <td key={key}>{toString(row[key])}</td>)}
            </tr>)}
        </tbody>
    </table>
}

For example:

let exampleData = [
    { name: "Alex", age: 13, date: new Date() },
    { name: "Dominic", age: 313, date: new Date() },
    { name: "Fiona", age: 33, date: new Date() }
]

<TableView object={exampleData} />

produces:

Table view

Sign up to request clarification or add additional context in comments.

Comments

0

Your problem is when rendering the JS Date. In your example data you create a date by using new Date() which indeed returns a JS Date Object. In order to render the date just convert it to a string format.

const tableContent = 
  <div>
    {exampleData.map((element,index) => { 
        return(
          <tr>
            <th scope="row">{index}</th> 
            {Object.keys(element).map((key)=>{
              const el = element[key]
              return(<tr scope="row">{el instanceof Date ? el.toUTCString() : el}</tr>)
             }
            }
           </tr>
        )
       })
     }
  </div>

You may also want to check how you're formatting your table. Here's a working fiddle: LINK

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.