0

I have a function that walks down a simple tree and calls functions at each step to print a menu:

renderMenuFx(menu, renderFx) {
    renderFx.startMenu()
    for (const entry of menu) {
        renderFx.startEntry()
        renderFx.renderEntry(entry.path.join(""), entry.title)
        if (entry.menuEntries) {
            this.renderMenuFx(entry.menuEntries, renderFx)
        }
        renderFx.endEntry()
    }
    renderFx.endMenu()
}

and it works when logging to console:

this.renderMenuFx(tree, {
    startMenu() { console.log('<ul>') },
    endMenu() { console.log('</ul>') },
    startEntry() { console.log('<li>') },
    endEntry() { console.log('</li>') },
    renderEntry(path, title) { console.log(`<a href="${path}">${title}</a>`) },
})

But it doesn't when I try to render it in React:

<div>

{
    f.renderMenu(this.tree, {
        startMenu() { return ( <ul> ) },
        endMenu() { return ( </ul> ) },
        startEntry() { return ( <li> ) },
        endEntry() { return ( </li> ) },
        renderEntry(path, title) { return ( <a href={path}>{title}</a> ) },
    })
}

</div>

Actually, the issue is that it doesn't compile, giving:

./src/components/Menu/MenuDyn.js
Syntax error: Unexpected token (141:37)

  139 |                     f.renderMenu(this.tree, {
  140 |                         startMenu() { return ( <ul> ) },
> 141 |                         endMenu() { return ( </ul> ) },
      |                                     ^

I'm obviously doing it wrong: what's the correct way to handle such situation?

4
  • Your login test and the jsx functions do different things. I’m pretty sure JSX elements have to be closed. So it’s not possible to render just an opening/closing tag. Commented Mar 26, 2020 at 16:57
  • Consider changing the perspective. Each “HTML” tag in JSX is actually a function (React.createElement) Commented Mar 26, 2020 at 17:00
  • it's quite simple ... pass tree as prop to some node component ... node renders children subnodes passing subtrees (or end-nodes) [as props] Commented Mar 26, 2020 at 17:08
  • @xadm (simple to some, difficult for others. Consider writing an answer?) Commented Mar 26, 2020 at 17:33

1 Answer 1

1

Simple example to start experiments:

in some <Menu menu={someData} /> class component

render () {
  return (
    <ul>
      {this.props.menu.map((entry) => (
        <Entry key={entry.id} data={entry}></Entry>
      ))}
    </ul>
  )
}

rendered (functional) subcomponent:

const Entry = props => (
  <li>
    {props.data.title}
    {props.data.menuEntries && (
      <Menu menu={props.data.menuEntries} />
    )}
  </li>
)
Sign up to request clarification or add additional context in comments.

2 Comments

Yup, thanks. I found some references about recursive React components and came up with something similar; the only thing I don't like is that in this way the tree structure is explicit in the rendering code, whereas in the function-based one it's not - or, better, it is factorized in a single place.
@watery usually it's full of options, conditions ... you can explore other possibilities like github.com/iannbing/react-simple-tree-menu ... simple in use but it can be less readable

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.