How to generate dom recursively from json by react.createElement

now we need to develop a website to generate front-end pages based on the node ID saved in the database. For example, the json data is:

let data=[
    {"id":1,"pid":0,"type":"div"},
    {"id":2,"pid":1,"type":"ul"},
    {"id":3,"pid":2,"type":"li"},
    {"id":4,"pid":3,"type":"span"},
    {"id":5,"pid":0,"type":"div"},
    ...
]

the data result of a regular front-end page should have hundreds of array elements. Pid is the parent node id,. If it is the top-level node (that is, the direct child node of the body tag), pid=0;

data.map((evt,i)=>{
    React.cteateElement("div",{},[children...]);
})

the actual data is more complex than this, and you need to determine the node type, whether to generate div or ul,span or other tags. This creation problem cannot be solved with JSX syntax. Because it is also unknown how many layers of type, the node type is taken from data, it varies according to the json result.
the final generated page might look like this:

<div data-id="1" data-pid="0"></div>
<div data-id="2" data-pid="0">
    <div data-id="3" data-pid="2">
        <ul data-id="5" data-pid="3">
            <li data-id="6" data-pid="5">
                <!---->
            </li>
            <li data-id="7" data-pid="5"></li>
        </ul>
    </div>
    <div data-id="4" data-pid="2"></div>
</div>

how to insert a non-top-level node into children. If a top-level node is nested with multi-level child nodes, you need to use recursion. How to write this recursion in createElement? I don"t have a clue. Ask God for help.

Feb.26,2021

can you tell me why jsx grammar can't solve this problem?
according to the sample you provided, the first and second layers are div , the third layer is ul , and the fourth layer is li .
and then use map return to come out. There is no need for recursion.


The children should be ready when

cteateElement
so the instance should be created from the child to the parent

requires 2 recursions

  • the first recursion is used to organize json
  • the second one is used to create an instance

refer to the following code:

class App extends React.Component {
  constructor() {
    super()
    this.badJson = [
      {id: 1, pid: 0, type: 'div'},
      {id: 2, pid: 1, type: 'ul'},
      {id: 3, pid: 2, type: 'li'},
      {id: 4, pid: 3, type: 'span'},
      {id: 5, pid: 0, type: 'div'}
    ]
  }

  handleJson(val, pid) {
    if (val.pid == pid) {
      const children = this.badJson.map(val2 => this.handleJson(val2, val.id)).filter(x => x)
      if (children.length) val.children = children
      return val
    }
  }

  createNodes({id, pid, children, type}) {
    return React.createElement(
      type || 'div',
      {key: id},
      children ? children.map(val => this.createNodes(val)) : id
    )
  }

  render() {
    //  JSON
    const goodJson = this.badJson.map(val => this.handleJson(val, 0)).filter(x => x)

    return <div>{goodJson.map(val => this.createNodes(val))}</div>
  }
}
Menu