purescript-thermite
purescript-thermite copied to clipboard
Nesting Specs
Thermite has the concept of sequencing Spec
s via the Semigroup
instance, but sometimes you want to nest the markup of a Spec
inside another. Lately I've been using this helper function:
wrap :: forall eff state props action.
Spec eff state props action ->
Spec eff state props action ->
Spec eff state props action
wrap parent child = simpleSpec pa rn
where
pa a p st k = do
view _performAction parent a p st k
view _performAction child a p st k
rn k p st children = view _render parent k p st (view _render child k p st children)
At this point, I'm not sure whether this re-appropriation of the children argument is elegant or hacky. Does it make sense to add a function like this to Thermite? I'm definitely open to better names as well.
Hmm, that's interesting. I expected users would pass a Spec
for any inner component as a function argument, but I suppose it makes sense to use the children
property instead. I suppose it is a little hacky, but then that argument has always been undocumented, so we can call this the default going forward, and document that any React-provided children will be passed in at the top level.
I think the name wrap
might be used though.
Another question is: should the children be passed as a singleton array? Or even pass an array of child Spec
s?
This is what I came up with:
render dispatch _ state _ =
[ R.div [...] [ view T._render childSpec dispatch {} state [] ]
childSpec
can of course be focused to use some substate/action. Is there a more idiomatic way to do that?
Furthermore, what would props be used for in Thermite? When using focused specs there's only one global state anyway, or am I missing something?
I'm not sure how useful that would be, but if Render
was a Reader
monad, it would be possible to pass down dispatch/state
to child specs implicitly.
@pkamenarsky I think focusing would use a separate call to focusState
etc.
Props are used at the top-level when the full component is integrated into a larger React application.
I'm interested in the Reader
approach, for sure, but it adds a cognitive overhead for new users which I'd like to avoid. Right now, all you need to get started is functions and data types (I consider the lens stuff to be an advanced feature, but even then, you don't need to know about type classes or monads to use it).
@paf31 Yes, focusing is a separate call (i.e. childSpec = focus ...
). What I meant though is that it would be cool to be able to nest components the same way other elements are nested:
[ R.div [...] [ chidComponent [...] [...] ]
without having to call render
explicitly. But I guess that would only be possible with the Reader
approach - and I agree, the mental overhead probably doesn't justify that.
re props - so if the whole application is written in Thermite, props are basically useless?
Pretty much, on the props
thing.
I have an almost identical function
nestSpec :: forall eff state props action. T.Spec eff state props action -> T.Spec eff state props action -> T.Spec eff state props action
nestSpec parent child = T.simpleSpec performAction render
where
performAction a p st = do
view T._performAction parent a p st
view T._performAction child a p st
render k p st children = view T._render parent k p st (view T._render child k p st children)
Would you be open for a PR?