thomashoneyman/purescript-halogen-hooks

Is it possible to pass hooks around?

prescientmoon opened this issue · 4 comments

This is my favorite react state management lib, so I decided to try and create a custom halogen hook which does the same thing.

Now the thing is, that lib involves passing state, useState and promap to the child component. Sure, I can pass the actual state, but if I pass the state token and the child uses it to modify the state will it change the state of the parent who passed the token down or will it just error out cause there's no state with that token?

And if it will error out, how could I implement this using outputs & queries instead?

Maybe you could create a bus in your root component, the setState function that you pass to your child could write the new state to the bus and your root component could then update the state inside an useLifecycleEffect handler. Not sure but it might be that #5 needs to be solved first.

Maybe you could create a bus in your root component, the setState function that you pass to your child could write the new state to the bus and your root component could then update the state inside an useLifecycleEffect handler. Not sure but it might be that #5 needs to be solved first.

Thanks :D

@mateiadrielrafael Sorry, I missed this!

Now the thing is, that lib involves passing state, useState and promap to the child component. Sure, I can pass the actual state, but if I pass the state token and the child uses it to modify the state will it change the state of the parent who passed the token down or will it just error out cause there's no state with that token?

The token should associate properly. When you interpret nested Hooks they ultimately all end up in the same component, so the state token should still be associated with the right cell in state.

And if it will error out, how could I implement this using outputs & queries instead?

You can't use outputs and queries in Hooks. Those are specific to parent / child components.

You can replace outputs (which notify a parent component of an event, which the parent can handle) by instead accepting a callback to run when the event happens internally. You can replace queries by returning HookM functions from your Hook, so the user of the Hook can call those functions when they'd like -- either just performing some action, or also returning some data as a query could.

For example (not tested, but basically this):

myHook
  :: forall m
   . (Int -> HookM m Unit)
  -> Hook m (UseState Int) { count :: Int, increment :: HookM m Int }
myHook onIncrement = Hooks.do
  count /\ countToken <- Hooks.useState 0
  Hooks.pure
    { count
    , increment: do
        n <- Hooks.modify countToken (_ + 1)
        onIncrement n
        pure n
    }

Someone using this hook can replace getting an "Incremented" message by passing in a callback "onIncrement" to run when the state is modified. And this hook returns an action, "increment", which both modifies internal state and returns a value, which is a replacement for a query.

Maybe you could create a bus in your root component, the setState function that you pass to your child could write the new state to the bus and your root component could then update the state inside an useLifecycleEffect handler.

This is also an option! If you start to accept a lot of callbacks and return a lot of actions you might want to move to this kind of approach instead to keep things clean especially as you start to get lots of recursively-called functions.

I'm going to close this issue, as I believe the question has been answered, but please feel free to re-open or follow up here if you have more.