2

I have this JSON data I am trying to render as a list.

[{
    "id": "1",
    "name": "Bill"
}, {
    "id": "2",
    "name": "Sarah"
}]

I am trying to display the data such that I pass a title of the data and the id's as parameters from Parent class to Child class and the latter prints the data as list.

export default class Parent extends Component {
  render() {
    return (
        <div>
        <Child
          title={"Group 1"}
          options={this.props.data.name}
        />
        </div>
    );
  }
}

Here's my Child class:

export default class Child extends Component {
  render() {
    var data=this.props;
    var title=this.props.title;
    var name=this.props.name;
    return (
      <ul>
        <h4>{title}</h4>
        <div>{this.props.map(item=>
          <li>{name}</li>
        )}
        </div>
      </ul>
    );
  }
}

What I don't understand is how to use map in the Child class to display data. I know that I shouldn't write this.props.map(item=>. I am new to React and would appreciate some help fixing this.

3
  • What is your JSON object variable called? Commented Nov 14, 2017 at 12:53
  • Please refer this answer : stackoverflow.com/questions/22876978/loop-inside-react-jsx Commented Nov 14, 2017 at 12:54
  • It's called "data" like I wrote this.props.data.name in Parent class Commented Nov 14, 2017 at 12:56

4 Answers 4

1

Well, first you have to use JSON.parse() on your json, so it becomes a javascript object, you also have to make sure you are passing the props to your Child right. Then, you can map like this:

this.props.data.map((item,i) => <li key={i}>{item.name}</li>)

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

1 Comment

Is this the right way to pass an attribute of the JSON object, say "name" ?{this.props.data.name}
1

Just pass your data as prop from parent component and you can access it in child component.

let {Component} = React;

const data = [{
    "id": "1",
    "name": "Bill"
}, {
    "id": "2",
    "name": "Sarah"
}]

class Child extends Component {
  render() {
   let {data, title} = this.props;
   
    return (
      <ul>
        <h4>{title}</h4>
        <div>{data.map(item=>
          <li key={item.id}>{item.name}</li>
        )}
        </div>
      </ul>
    );
  }
}

class Parent extends Component {
  render() {
    return (
        <div>
          <Child
            title={"Group 1"}
            data={this.props.data}
          />
        </div>
    );
  }
}

ReactDOM.render(
  <Parent data={data} />,
  document.getElementById('app')
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>

You can also call map method inside parent component and for each element in your data render Child component. Also only li element can be direct child of ul.

let {Component} = React;
const data = [{"id": "1","name": "Bill"}, {"id": "2","name": "Sarah"}]

class Child extends Component {
  render() {
    let {name} = this.props;
    return <li>{name}</li>
  }
}

class Parent extends Component {
  render() {
    return (
        <div>
          <h1>{"Group 1"}</h1>
          <ul>{this.props.data.map(item => {
                return <Child key={item.id} {...item} />
              })}
          </ul>
        </div>
    );
  }
}

ReactDOM.render(
  <Parent data={data} />,
  document.getElementById('app')
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>

Update: for nested children you can React.cloneElement to dynamically add child nodes.

let {Component} = React;
const data = [{ "id": "1", "name": "Bill" }, { "id": "2", "name": "Sarah", "childnodes": [{ "id": "3", "name": "Some name", "childnodes": [{ "id": "4", "name": "Last" }]}] }]

class Child extends Component {
  render() {
    let {name} = this.props;
    return <li>
      {name}
      {this.props.children ? <ul>{this.props.children}</ul> : ''}
    </li>
  }
}

class Parent extends Component {
  constructor(props) {
    super(props);
    this.renderNodes = this.renderNodes.bind(this);
  }
  
  renderNodes(data) {
    return data.map(item => {
      let child = <Child key={item.id} {...item} />
      
      if(item.childnodes) {
        child = React.cloneElement(child, {
          children: this.renderNodes(item.childnodes)
        })
      }
      
      return child;
    })
  }

  render() {
    return (
        <div>
          <h1>{"Group 1"}</h1>
          <ul>{this.renderNodes(this.props.data)}</ul>
        </div>
    );
  }
}

ReactDOM.render(
  <Parent data={data} />,
  document.getElementById('app')
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>

1 Comment

Thanks a lot. Is it possible to modify the second approach for recursive check for example the child nodes like here but passing only props.name as argument in Child component: [{ "id": "1", "name": "Bill" }, { "id": "2", "name": "Sarah", "childnodes": [{ "id": "3", "name": "4" }] }]
0

let's don't use map in the child... try this:

let data = [{
    "id": "1",
    "name": "Bill"
}, {
    "id": "2",
    "name": "Sarah"
}]

user map in parent component:

export default class Parent extends Component {
  render() {
    return (
        <div>
        <div>Group 1</div>
        <ul>
          {data.map(item => <Child
            options={item}
          />)}
        </ul>
        </div>
    );
  }
}

enhance the child component :

export default class Child extends Component {
  render() {
    let {options:{name}} = this.props
    return (
      <li>{name}</li>
    );
  }
}

Comments

0

You have a few issues with your code:

  1. You need to pass your JSON object down from your Parent to your Child-component. If it's called data, then do:

    <Child
      title={"Group 1"}
      options={this.props.data}
    />
    

    I suggest using data instead of options to prevent confusion, but that's up to you. Also, you cannot pass this.props.data.name because this.props.data is an array of objects.

  2. Now that options is an array, we can properly use map(). You were trying to use map() on this.props, which is incorrect. So try instead:

    <div>
      {this.props.map(item=>
        <li>{item.name}</li>
      )}
    </div>
    
  3. Also, <ul> elements can only have <li> as their direct children. You have placed <h4> and <div> elements as its children. Instead wrap those inside an <li> element.


Full demo:

const data = [
  {
    "id": "1",
    "name": "Bill"
  }, {
    "id": "2",
    "name": "Sarah"
  }
];

class Parent extends React.Component {
  render() {
    return (
      <div>
        <Child
          title={"Group 1"}
          options={this.props.data}
        />
      </div>
    );
  }
}

class Child extends React.Component {
  render() {
    var title = this.props.title;
    return (
      <div>
        <h4>{title}</h4>
        <ul>
          <li>
            <div>
              {this.props.options.map(item=>
                <li>{item.name}</li>
              )}
            </div>
          </li>
        </ul>
      </div>
    );
  }
}

ReactDOM.render(<Parent data={data} />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

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.