Changes in v6
This is a crash-course on the changes from Halogen 5 to Halogen 6. Please open an issue or PR if you notice missing information or ways this guide could be improved!
Halogen 6 introduces several quality-of-life improvements for using Halogen on a day-to-day basis, without major changes to how you use the library to build your applications. It's an intentionally small release which adds polish to the library and which is the first version to support version 0.14 of the PureScript compiler.
If you are migrating an application from Halogen 5 we recommend reading through the full transition guide. However, you can also hop directly to a relevant section using the table of contents below.
- PureScript 0.14
- Component Types
- Event Handler Types
- Query Helper Functions
- Subscriptions
- Other Changes
PureScript 0.14
Halogen 6 is the first version of Halogen compatible with PureScript 0.14. You'll need PureScript 0.14 to compile the library, and if you're upgrading your application to use PureScript 0.14 then you'll need to be on Halogen 6. We know it can be painful dealing with compiler changes and library changes, so we've kept this release intentionally small.
Component Types
Component types have been simplified by removing the surface
parameter.
In Halogen 5 (and prior versions), components and the internal functions which manage them carried a surface
parameter which indicated the target for the UI to render. As no one ever wrote an alternate target from HTML
, Halogen applications have always fixed this parameter to HTML
in component definitions, as in:
import Halogen as H
import Halogen.HTML as HH
myComponent :: forall q i o m. H.Component HH.HTML q i o m
In Halogen 6 the surface
parameter has been removed. The only real user-visible change is that components and functions which operate on them no longer carry the surface
parameter.
import Halogen as H
myComponent :: forall q i o m. H.Component q i o m
This is a breaking change, but one which is easily fixed: remove this parameter from your components and any related functions and types.
Added in #616.
Event Handler Types
We've also made event handlers a little nicer to work with. The Maybe action
return value has been removed from event handlers, which now return action
directly.
In Halogen 5, when you wanted to respond to a click event, or a message from a child component, the output was of type Maybe action
. This allowed you to selectively emit outputs (you could emit Nothing
for some events). In practice, though, few do this.
To remove friction around such a common task, these handlers no longer return in Maybe
in Halogen 6. Instead, they return the action directly. Here is how some simple render code would change from Halogen 5 to Halogen 6:
HH.div_
[ HH.button
- [ HE.onClick \_ -> Just Clear ]
+ [ HE.onClick \_ -> Clear ]
[ HH.text "Clear" ]
- , HH.slot _id unit component unit (Just <<< Handle)
+ , HH.slot _id unit component unit Handle
]
You're no longer able to ignore the output of a child component by providing a handler \_ -> Nothing
. Instead, you can use the slot_
function if you don't care about a child component's output. This code from Halogen 5:
HH.slot _id unit component unit (\_ -> Nothing)
becomes this code in Halogen 6:
HH.slot_ _id unit component unit
Note: You can recover the old Halogen 5 behavior by adding a DoNothing
constructor to your action type, or by wrapping your action type in Maybe
.
Query Helper Functions
We've simplified the helper functions which are used with queries so that you can use tell
and request
directly, rather than use them in conjunction with the query
and request
functions.
In Halogen 5, to execute a query you would use the query
function and combine it with the request
function (for request-style queries, which return a result) or the tell
function (for tell-style queries, which don't return a result). This was always a bit difficult to explain and easy to trip over when writing queries yourself.
Here's how you would execute a request-style and then a tell-style query in Halogen 5:
handleAction = do
a <- H.query _a unit (H.request Child.SomeRequestQuery)
_ <- H.query _a unit (H.tell Child.SomeTellQuery)
In Halogen 6, you no longer use the query
function. Instead, you use request
and tell
directly. You also don't have to throw away the result of tell
, as it can already be safely discarded:
handleAction = do
a <- H.request _a unit Child.SomeRequestQuery
H.tell _a unit Child.SomeTellQuery
The old tell
and request
functions still exist in Halogen 6, but they've been renamed to mkTell
and mkRequest
and are only used when querying the root of your application. For example, this code in Halogen 5:
io <- runUI component unit body
state <- io.query $ H.request SomeRequestQuery
_ <- io.query $ H.tell SomeTellQuery
becomes this code in Halogen 6:
io <- runUI component unit body
state <- io.query $ H.mkRequest SomeRequestQuery
_ <- io.query $ H.mkTell SomeTellQuery
Added in #621.
Subscriptions
Event sources have been replaced with the new halogen-subscriptions
library. The previous implementation of event sources was built on top of coroutines
. This update simplifies the library internals and connects Halogen with a subscription management library that can be used independently of Halogen itself.
Notable changes include:
- The entire
Halogen.Query.EventSource
module has been removed and replaced withHalogen.Query.Event
which provides only aneventListener
function. The new function is a drop-in replacement for the oldeventListenerEventSource
, so all you need to do is update your import. affEventSource
andeffectEventSource
functions can be trivially replaced with code using thehalogen-subscriptions
library directly, so they have been removed. Examples of how to rewrite these functions are below.- The other helper functions and types from the
Halogen.Query.EventSource
module are no longer required. - The
subscribe
function andSubscribe
constructor no longer take anEventSource m action
to subscribe to. They take anEmitter action
instead. - The
HalogenIO
type returned by running your root-level component now contains amessages :: Emitter output
instead of asubscribe :: Coroutine.Consumer output m Unit -> m Unit
.
If you were previously using effectEventSource
, then you would change this Halogen 5 code:
import Halogen as H
import Halogen.Query.EventSource as ES
do
void $ H.subscribe $ ES.effectEventSource \emitter -> do
ES.emit emitter MyAction
pure mempty
with this Halogen 6 code:
import Halogen as H
import Halogen.Subscription as HS
do
{ emitter, listener } <- H.liftEffect HS.create
void $ H.subscribe emitter
H.liftEffect $ HS.notify listener MyAction
When running your root component, you'll also need to replace your use of coroutines. For example, this Halogen 5 code:
main :: Effect Unit
main = ...
io <- runUI component unit body
io.subscribe $ Coroutine.consumer \msg -> do
...
should be replaced with this Halogen 6 code:
main :: Effect Unit
main = ...
io <- runUI component unit body
_ <- liftEffect $ HS.subscribe io.messages \msg -> do
...
Other changes
Halogen 6 is an intentionally small release because it coincides with the PureScript 0.14 release. There are only a few other changes in the library to report:
- The
id_
function has been renamed toid
now thatid
has been renamed toidentity
in the PureScript Prelude.id_
continues to work, but has a deprecation notice and will be removed in the next version. See #717. - PureScript 0.14 deprecated the
SProxy
type in favor of the simplerProxy
type. For this reason, all usages ofSProxy
in Halogen have been replaced withProxy
. You can do the same in your application with a simple find/replace which replacesSProxy
withProxy
and the importData.Symbol (SProxy(..))
withType.Proxy (Proxy(..))
. - The
AttrName
,PropName
, andClassName
types from Halogen have been migrated into theweb-html
library and imported back into Halogen. This allows libraries to share these types rather than re-implement them over and over. These types are re-exported from Halogen, so your code doesn't need to change.