2

Recently I am trying to solve a problem where I have to render a document tree menu (hierarchical) from a nested JSON coming from a request call.

Say my JSON looks like this

[{
    "title": "Food",
    "path": "/root",
    "children": [{
        "title": "Veg",
        "path": "/root/Food",
        "children": [{
            "title": "Carrot",
            "path": "/root/Food/Veg",
            "children": [{
                "title": "Ooty carrot",
                "path": "/root/Food/Veg/Brinjal",
                "children": []
            }]
        }]
    }]
}, {
    "title": "Cloths",
    "path": "/root",
    "children": [{
        "title": "T shirt",
        "path": "/root/Cloths",
        "children": []
    }, {
        "title": "Shirt",
        "path": "/root/Cloths",
        "children": []
    }]
}]

I have to create the following DOM from the above JSON

enter image description here

SOLVED through jQuery:

I have the function ready to convert the JSON to DOM: in normal jQuery I would do something like the following:

$(function(){
    function get_tree(tree_data){
      dom += '<ul>';
      for(var i in tree_data){
        if(tree_data[i].children.length > 0){
          dom += '<li>';
          dom += '<a href="#" class="tree-parent-anchor">'+tree_data[i].title+'</a>';
          get_tree(tree_data[i].children);
          dom += '<li>';
        }
        else{
          dom += '<li>'+tree_data[i].title+'</li>'
        }
      }
      dom+= '</ul>'
    }
    var tree_data = JSON.parse($('pre').text());
    var dom= '<ul id="Menu-list">';
            get_tree(tree_data);
        dom+= '</ul>'
    $('div').append(dom);
})

In REACT.JS I tried this (ofcrse it doesn't works):

export default class DocTree extends Component{
    state = {treeData: [{
            "title": "Food",
            "path": "/root",
            "children": [{
                "title": "Veg",
                "path": "/root/Food",
                "children": [{
                    "title": "Carrot",
                    "path": "/root/Food/Veg",
                    "children": [{
                        "title": "Ooty carrot",
                        "path": "/root/Food/Veg/Brinjal",
                        "children": []
                    }]
                }]
            }]
        }, ...
        }]
    }

    render(){
        const tree_data = this.state.treeData;
        function get_tree(tree_data, dom){
              <ul>
                for(var i in tree_data)
                    if(tree_data[i].children.length > 0)
                        <li>
                            <a href="#" className="tree-parent-anchor">{tree_data[i].title}</a>
                            get_tree(tree_data[i].children);
                        <li>

                    else
                        <li>{tree_data[i].title}</li>
                </ul>

        var dom = <ul id="Menu-list">
            get_tree(tree_data);
        </ul>

        return(
            <div>
                {dom}
            </div>
        );
    }
}

I dont exactly how to achieve the same through React.js syntax

Please help me with - How do it in React.js (am using React.js 16.2.0)

2 Answers 2

5

You cannot use for loop within JSX, and secondly you can recursively render your tree after mapping over each object

const data =[{
    "title": "Food",
    "path": "/root",
    "children": [{
        "title": "Veg",
        "path": "/root/Food",
        "children": [{
            "title": "Carrot",
            "path": "/root/Food/Veg",
            "children": [{
                "title": "Ooty carrot",
                "path": "/root/Food/Veg/Brinjal",
                "children": []
            }]
        }]
    }]
}, {
    "title": "Cloths",
    "path": "/root",
    "children": [{
        "title": "T shirt",
        "path": "/root/Cloths",
        "children": []
    }, {
        "title": "Shirt",
        "path": "/root/Cloths",
        "children": []
    }]
}]


const MyComponent = ({data}) => {
   return (
    <ul>
      {data.map((m, index) => {
        return (<li key={index}>
          {m.title}
          {m.children && <MyComponent data={m.children} />}
        </li>);
      })}
    </ul>
  );
}
class App extends React.Component {

  
  render() {
     return <div>
        <MyComponent data={data} />
     </div>
  }
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="root"/>

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

Comments

2

You've misunderstood JSX.

Let consider it just like a server-side language (eg: PHP, ASP),

What you're doing is embed HTML and JSX, just like embed HTML and PHP.

Why? JSX is js and a JSX element is an object under the hood.

You can run some hello world JSX on https://babeljs.io/repl/ to see how JSX was transpile into ES5 (in case of ES5 browser), you'll understand JSX.

For more detail, you should read React fundamental, especially JSX in depth


Finally, this is the modification needed to work:

function get_tree(tree_data, dom){
  var elems = [];

  for(var i in tree_data)
    if(tree_data[i].children.length > 0)
      elems.push(<li>
          <a href="#" className="tree-parent-anchor">{tree_data[i].title}</a>
          {get_tree(tree_data[i].children)}
          </li>)
    else
      elems.push(<li>{tree_data[i].title}</li>)

  return <ul>{elems}</ul>
}

Btw, your code is bad in practice because you're new in React, you should consider @Shubham Khatri idea and follow his practice.

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.