Reputation: 453
I am trying to populate table data by importing json. However, getting below error: Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys { list }). If you meant to render a collection of children, use an array instead.
Below is the code I am using:
import reg from "./data/reg.json";
class TableRow extends Component {
render() {
const { data } = this.props;
const list = data.map(adata => {
return (
<tr>
<React.Fragment>
<td key={adata.FName}>{adata.FName}</td>
<td key={adata.LName}>{adata.LName}</td>
<td key={adata.Age}>{adata.Age}</td>
</React.Fragment>
</tr>
)//return
})//regionslist
return (
{ list }
);//return
} //render
} //class
class DTable extends Component {
render() {
return (
<Table striped bordered hover>
<TableHeader />
<tbody>
<TableRow data={this.props.data} />
</tbody>
</Table>
);
}
}
class DataTable extends Component {
render() {
return (
<DTable data={reg} />
);//return
} //render
}
Upvotes: 1
Views: 210
Reputation: 4176
I recreated your setup trying to reproduce your error. You can see what I reproduced here: Stackblitz. The issue seems to lie in the fact that your map creates some table rows, but there is no parent element to wrap them, which is required by JSX.
This can be fixed by wrapping {list}
inside of a React.Fragment
:
class TableRow extends Component {
render() {
const { data } = this.props;
const list = data.map(adata => {
return (
<tr>
<td key={adata.FName}>{adata.FName}</td>
<td key={adata.LName}>{adata.LName}</td>
<td key={adata.Age}>{adata.Age}</td>
</tr>
)//return
})//regionslist
return (
<React.Fragment>
{ list }
</React.Fragment>
);//return
} //render
} //class
Adding the React.Fragment
around the list items resolved the issue. You can see the working solution here: Stackblitz
As of React 16.2 (Read more) you also have the option to return empty JSX tags instead of typing out React.Fragment. The solution above would look like this:
class TableRow extends Component {
render() {
const { data } = this.props;
const list = data.map(adata => {
return (
<tr>
<td key={adata.FName}>{adata.FName}</td>
<td key={adata.LName}>{adata.LName}</td>
<td key={adata.Age}>{adata.Age}</td>
</tr>
)//return
})//regionslist
return (
<>
{ list }
</>
);//return
} //render
} //class
Lastly it is also possible to return an array of elements since React 16.0. If you would choose to do this the above code would look like this then:
class TableRow extends Component {
render() {
const { data } = this.props;
const list = data.map(adata => {
return (
<tr>
<td key={adata.FName}>{adata.FName}</td>
<td key={adata.LName}>{adata.LName}</td>
<td key={adata.Age}>{adata.Age}</td>
</tr>
)//return
})//regionslist
return [list];//return
} //render
} //class
A limitation of this option is however that a key has to be added to the items as React will otherwise throw this warning in the console:
Warning: Each child in a list should have a unique "key" prop.
Note that even if you omit this key it will still render properly.
Upvotes: 2
Reputation: 25506
Initially, there was a limitation in React
that you can only return a single element from render function but it has been changed after React 16
, Now you can return the array of elements.
In your case, you are trying to array of the element without mentioning that it's an array due to which you have to group it using Fragment
.
This issue can be solved in two ways:
Wrap array inside Fragment
or any other container element (But in that case it will add one extra node to the DOM which is bad and to solve that issue Fragment's
are introduced. for more details check here: https://reactjs.org/docs/fragments.html)
return (
<React.Fragment>
{ list }
</React.Fragment>
);
Return an array.
return ([ list ]);
Upvotes: 0