Rendering components without the slot function

I have a simple function that must perform an effect to render some Halogen HTML.

Without the effect, it would look like this:

example :: ∀ w i . String -> HH.HTML w i

This allows me to easily attach it into the render function of any component:

render :: ∀ m . State -> H.ComponentHTML Action () m
render state = HH.div_ [ example ]

However, as I said in the beginning, I need to perform an effect in that function. So, the function actually looks like this:

example :: ∀ w i m . MyMonad m => String -> m (HH.HTML w i)

In that way, I cannot easily attach it into the Halogen HTML. I could perform the effect in the Initialize action of the component and then add the result into the state, but that wouldn’t work for me because I need to use that function several times in the render function.

My last option is making a component out of it. It would look like this:

example :: ∀ q o m . MyMonad m => H.Component HH.HTML q Input o m

But now I would have to use the slot function in every place I attach this component, which would require me to add a lot of proxies and labels throughout the render function. Since this component has no query or output, and I don’t need to keep any track of it, I would like to know if there is a way to attach this component without using the slot function.

Any ideas?
Other solutions are welcome.

Thank you!

1 Like

I believe the slot function is always necessary, even for simpler child components (assuming they can’t be replaced by pure functions). The end of this section of the halogen guide might provide some better justification why.

Hooks might make this more ergonomic. Here’s an example of display-only child components from the cookbook (ComponentsInputHalogenHooks) that’s been modified to include two effects (logging and random number generation).

Of course, that particular example could also be modified to run the effects in the parent component and replace the child components with pure render functions.

I’m curious what effects you need to run that can’t be performed by the parent with the necessary results stored in parent state. Understandable that this could be pretty inconvenient with multiple purely-rendered “children”.


Edit: You can wrap the slot calls in a convenience function to get pretty close to your original effect-free example signature, but you’ll still need to pass a unique id to each (otherwise you’ll get lots of extra unwanted DOM elements on each rerender). mapWithIndex makes this less tedious. Here’s an example with that approach.

Thank you for your reply @milesfrain

I see… I guess I will have to take another approach to solve my problem.

The function in question is responsible for translating text. The translation file is huge, must file be fetched from the server. The keys and values cannot be hard-coded in the application thus used as pure functions (the only translation library in PS works in this way), that’s why it is an effect.