Closed marcinkoziej closed 1 year ago
Some really great work in this! I was hoping we'd figure out a way to avoid having to wrap components in a createElement
call (hence what I was hoping use <- component
would do) but I also came to the conclusion that it wasn't avoidable. On the bright side being able to do use count, set_count <- state(0)
is great! (Though I'm still inclined to think it should stay taking a function. Maybe that could be a separate hook like state_fn
?)
I think this is definitely a good path forward though. There has been talk about default arguments in Gleam which may help in the future but wont' be coming any time soon.
@brettkolodny I have added a state_lazy
that accepts a function
Hi @brettkolodny !
In context of the unable to maintain state issue and because I am live-testing
react_gleam
in my personal react-native project, I am trying to make sense of how this package could work in a way that benefits of correctness (coming from types and program structure) and better DX (less verbose, versatile, but concise).A few observations/thoughts:
(props) => Element
functions. When using JSX, we employ the JSX mechanics that takes tag + its attributes, converts them into a JS object, and then calls this function. In current version ofreact_gleam
, we also do this: we convert our Gleam types to Dynamic, so they work withattribute.Property
, and then in a function component, we receive Dynamic props that we have to decode again. However, the JSX is converted toReact.createElement(function, props, childrem)
, whereprops
is an object. So why not just pass a Gleam type, without converting it both ways?.pub external fn muiButton(props: MuiButtonProps) -> Element = "@material-ui/core" "Button"
, and create MuiButtonProps type that matches the props used by library, and use them as follows:element.create(muiButton, MuiButtonProps(primary: True, color: "#231234"), [element.text("Click me")])
Option(a)
types, which gets converted toa
orundefined
, or we declare the props to contain a subset of imported props (just ones we use). The last option doesn't make sense for distributing such bindings though. Or perhaps such components should accept aDynamic
and that's it.element.node()
kind of component creation for html tags (where the component is no a function but string), and where we passList(Attribute)
- it would be hard to create a type for all possible html tags...element.node
could also be used for externally loaded components, if declaring a prop type in advance (point 2) is not good DX. We could haveelement.native_node(fn () -> Element, List(Attributes), List(Element))
or similar, where 1st argument is function, not a string. We could even make it a default and have a function for each tag, eg:pub fn div () -> Element = "ffi.js" "div"
and thenexport const div = (props) => (<div {...props}>{...props.children}</div>);
...and this way you can't really skip a call to a hook, because the callback structure orders it..
Element
orContext
. I've put them in mainreact_gleam.gleam
file to avoid import loops; however,Attribute
is still inattribute.gleam
because it's not used much elsewhere. Consistency would be useful here, but I am not sure how to achieve it - it also makes sense to put types in relevant domain-submodules.Check out this PR for proposed changes, and here is a changed example from the issue - which works with these new primitives: