Here’s an implementation of `val styledComponent =...
# javascript
m
Here’s an implementation of
val styledComponent = styled(someFunctionalComponent) { css { … } }
. Took me a few hours to figure that one out 😮
Copy code
fun <P> styled(component: FunctionalComponent<P>, handler: StyledElementBuilder<P>.(props: P) -> Unit): FunctionalComponent<P> where P : RProps, P : WithClassName {
    val buildStyled = styled(component.unsafeCast<RClass<P>>())
    val styledComponent = { props: P ->
        buildElement {
            buildStyled {
                val dynamicAttrs = attrs.asDynamic()
                val dynamicProps = props.asDynamic()
                props.getOwnPropertyNames().forEach { propertyName ->
                    dynamicAttrs[propertyName] = dynamicProps[propertyName]
                }

                handler(props)
            }
        }
    }

    if (js("process.env.NODE_ENV !== 'production'") as Boolean) {
        val displayName = component.asDynamic().displayName as String?
        if (displayName != null)
            styledComponent.asDynamic().displayName = "styled.$displayName"
    }

    return styledComponent
}
b
m
That’s not a good approach. It only exposes extension functions to
RBuilder
. If you create a component you need it as an
RClass
instance. Otherwise you can’t use it with high-order components like
memo(…)
or
styled(…)
.
b
Correct, that one only helps with functional components
m
No, it’s exactly where it doesn’t help 😅 At least not beyond the simple-most use cases.
b
You're right, just read your use-case properly...
b
There’s a ticket to support styling when I get some free time to figure out what the API will look like and
memo(…)
should be pretty easy to support as an annotation property. There’s probably also a way the library could provide the backing RClass for combining with other libraries. But you are correct, right now the library only supports the most basic of use cases but mainly because I don’t have a lot of experience with React and I haven’t needed anything more. Very happy to take suggestions on how to make the library better.
m
That’s not how the concept of high-order components works in React 😅
styled
and
memo
are just 2 of unlimited potential use cases.
Think of React components as definitions. You need to be able to pass them around and wrap them in other definitions like
styled
or
memo
. Everybody can define such wrapping definitions. They’re called high-order components.
That’s not really possible with function approach because the function only gets invoked when the definition is actually applied to create an element for a component.
It makes more sense to generate `val`s instead that can be passed around.
b
The library automatically generates a
external interface ComponentProps : RProps
from the function parameters and generates a
val COMPONENT: RClass<ComponentProps>
which contains the body of the function rewritten to use the properties. The original function is then transformed to call
invoke
on the resulting
COMPONENT
. So it is very possible the library could somehow provide access to these generated interfaces and properties.
m
Sounds good. How does it know what super interfaces my props need?
b
Because it controls everything and doesn’t expose anything, right now it just assumes RProps.
m
Ah I see
b
Again, right now it only supports the most basic of functional components. But since it automatically generates everything you would normal hand write, there is potential for it to support a lot more. Not saying it fits your use case, but it’s not quite as simple as just RBuilder functions. 🙂
m
Will be interesting to see how much code it saves at the end.
Copy code
fun RBuilder.Hello(name: String) {
I don’t use that pattern at all 🤔
b
There’s a fully functional sample project here which has a lot more components to it. Still small, but might give you a better idea.
m
I gave up on
styled
. It’s just not a good fit for Kotlin. High-order-components in general are problematic in Kotlin. I’ll avoid them now. That means
<http://RBuilder.xyz|RBuilder.xyz>
is the best option now 🙂