pugjs / babel-plugin-transform-react-pug

A plugin for transpiling pug templates to jsx

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support Render Props

ezhlobo opened this issue · comments

What is "Render Props"?

https://reactjs.org/docs/render-props.html

It's important to use this because Context API works via this approach. React is currently testing hooks, which will simplify the whole work with pug, but still we need to either have a good support of it or add information to the README.

How it works now

So now we support this way to use render props:

function render(item) {
  return pug`
    p= item
  `
}

const test = pug`
  Child
    ${item => pug`
      p item
    `}
    
  Prop(children=${item => pug`
    p item
  `})
  
  ExternalChild
    = render
    
  ExternalProp(children=render)
`

Check it out

How to improve?

I'm happy to know any crazy idea to make it more attractive in use.

I think the best bet might be some new syntax:

const test = pug`
  Child
    =>(item)
      p item
    
  Prop
    =>children(item)
      p item
     
  ExternalProp(children=render)

This would require a plugin the the parser and the lexer. N.B. not set on this syntax, just bike shedding.

@ezhlobo, thanks for creating this issue. If we add this feature we have our JSX killer ;) However, I like @ForbesLindesay suggestion a lot, super clean and minimal. It feels just a bit unfamiliar because of the reverse order of => and (item) but I don't have a better suggestion yet.

Also one note in this context: react-router-dom differentiates with its Router component between component=, render= and actual children. So, basically render= does not equal giving Route children: https://reacttraining.com/react-router/core/api/Route/route-render-methods

So, we'd need a render prop syntax which works as a child but also inline as attribute value. Hope I was clear.

From my example:

const test = pug`
  Route
    =>render(routeProps)
      h1 Route Contents
`;

Would become:

const test = <Route render={(routeProps) => <h1>Route Contents</h1>} />

still not a huge fan of the syntax though.

commented

I'm pretty unhappy about that syntax, too...

For the sake of consistency, here's how I see the unsugared version:

const test = pug`
  Route(render=(routeProps)=>${pug`
    h1 Route Contents
  `})
`
commented

While we're considering parser & lexer plugins, we could add to the babel plugin to re-purpose the embedding syntax we already have: (adding place attribute to clarify attribute usage)

const test = pug`
  Route(place='top' render=(routeProps)=>#[
    h1 Route Contents
  ])
`

I especially am uncomfortable with this one:

const test = pug`
  Nav(place='top' #render({content})[
    h1= content
  ])
`

AKA:

const test = pug`
  Nav(
    place='top'
    #render({content})[
      h1= content
    ]
  )
`

We could introduce (BAD IDEA) escapes that stop further indentation to get the shorthand:

const test = pug`
  Nav \
    place='top'
    #render({content}) \
      h1= content
`

Starting to smell like coffeescript. I think we're just hitting the integration limits of template literals here.

As a completely alternative approach, what if we were to embed js in pug rather than this way around?