cool_stuff_coming
cool_stuff_coming

Reputation: 453

ReactJS - reading json data

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

Answers (2)

etarhan
etarhan

Reputation: 4176

Problem

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.


Solution

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


Alternatives

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

mkb
mkb

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:

  1. 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> );

  2. Return an array.

    return ([ list ]);

Upvotes: 0

Related Questions