Notable changes to Hooks are documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Breaking changes (😱!!!):
New features:
Bugfixes:
Other improvements:
Breaking changes (😱!!!):
- Add support for PureScript 0.15 and Halogen 7, dropping support for previous versions of the compiler and Halogen. (#74 by @CarstenKoenig) This is a breaking change because of the upgrade in dependencies only. The code continues to work as-is.
Breaking changes (😱!!!):
-
Add support for PureScript 0.14 and Halogen 6, dropping support for previous versions of the compiler and Halogen. (#71 by @CarstenKoenig, #72 by @thomashoneyman)
-
Move to a single index for hook types. (#32 by @thomashoneyman)
Using a single index for Hook types simplifies the Hooks implementation and makes defining your own Hooks easier and less confusing. It also allows the library to drop its dependency on
indexed-monad
.Previously, Hooks were defined as an indexed monad with parameters to track the before and after state of a Hook bind:
-- Old approach type Hook m (newHooks :: Type -> Type) a = forall hooks. Hooked m hooks (newHooks hooks) a newtype Hooked m hooks newHooks a = Hooked (Indexed (Free (UseHookF m)) hooks newHooks a) bind :: forall a b x y z m . Hooked m hooks hooks' a -> (a -> Hooked m hooks' newHooks b) -> Hooked m hooks newHooks b
Now, Hooks are defined with a custom
HookType
and each bind produces a new, single index made up of all the hook types in use.-- New approach data HookType newtype Hook m (h :: HookType) a = Hook (Free (UseHookF m) a) foreign import data Hooked :: HookType -> HookType -> HookType infixr 1 type Hooked as <> bind :: forall h h' m a b . Hook m h a -> (a -> Hook m h' b) -> Hook m (h <> h') b
This is a breaking change because it changes how you define your Hook types in Halogen Hooks. First, Hooks are now written in the order they occur.
-- Assume UseState, then UseEffect, then UseRef in the code -- Previously: this reads backwards, as state transitions 'away from' the -- hooks type variable UseRef Int (UseEffect (UseState Int hooks)) -- Now: this reads in the order hooks are applied in the code, where -- `Pure` represents the call to `pure` UseState Int <> UseEffect <> UseRef Int <> Hooks.Pure
Second, you no longer use a newtype to define Hooks. Instead, you'll foreign import a data type to represent your Hook type and use the
HookNewtype
type class.-- Before type UseX' hooks = UseState Int (UseEffect hooks) newtype UseX hooks = UseX (UseX' hooks) derive instance newtypeUseX :: Newtype (UseX hooks) _ -- After type UseX' = UseEffect <> UseState Int <> Hooks.Pure foreign import data UseX :: Hooks.HookType instance newtypeUseX :: HookNewtype UseX UseX'
New features:
Bugfixes:
Other improvements:
- Docs: Added technical documentation that covers the main concepts used in the internal implementation (#59 by @thomashoneyman).
- Docs: Added a changelog to record changes to the library over time (#62 by @thomashoneyman).
- Tests: Added performance tests to measure the performance impact of changes (#53 by @thomashoneyman, #56 by @thomashoneyman).
- Updated the Nix shell to use PureScript 0.14 tooling
This release ensures that state-modifying HookM
code can't be passed from one component to another without throwing an immediate exception. HookM
code that modifies state which is written in one component must be evaluated in that component.
Bugfixes:
- Throw exception if state-modifying
HookM
code passed between components (#44).
Other improvements:
- Updates Spago package set and generated Bowerfile
This release updates module exports.
Bugfixes:
- Re-export
memoComponent
from the mainHooks
module (#43).
This release includes small internal performance improvements.
Improvements:
- Use
substFree
instead offoldFree
internally (#33). UsingfoldFree
is convenient, but it incurs some overhead due to aMonadRec
constraint on the monad you interpret into. Switching tosubstFree
eliminates this overhead, giving the library a modest performance improvement.
This release changes how users update state in Hooks.
Breaking changes (😱!!!):
-
Return to state identifiers instead of returning just a modify function (#31).
The previous release replaced state tokens with a simply
modify
function returned by theuseState
hook. For a variety of reasons this turned out to be not a change worth making, and it has now been reverted. See #30 for more details on why this happened.If you liked using a modify function instead of a token, you can still do that:
state /\ modifyState <- map Hooks.modify_ <$> Hooks.useState 0 let handleClick = modifyState (_ + 1) Hooks.pure ...
This release changes how users update state in Hooks.
Breaking changes (😱!!!):
-
Replace state tokens with a modify function (#29).
The previous versions of Hooks returned a state token from the
useState
hook, which could then be passed to theput
,modify
,modify_
, andget
functions we're all used to from HalogenM. Now, theuseState
hook returns a modify function directly which can be used to update the state. See #29 for more details on why this matters.This code from v0.2.1:
state /\ stateToken <- Hooks.useState 0 let handleClick = Hooks.modify_ stateToken (_ + 1) Hooks.pure ...
Would now be written like this:
state /\ modifyState <- Hooks.useState 0 let handleClick = modifyState (_ + 1) Hooks.pure ...
Now that there isn't a
get
function, if you need to get the most up-to-date state in an asynchronous function, you should copy the relevant part of state to a mutable reference so the function can read the reference during its execution. This is the same pattern you should use if you need to do the same with component input. #29 also introduces auseGet
example Hook which makes this easy and convenient.
This release fixes several bugs and changes some types used in the Halogen Hooks library.
Breaking changes (😱!!!):
-
Introduce tokens for all component-only features, not just queries (#22).
Hooks support writing functions for stateful logic, which are then interpreted by a Halogen component. However, some component features do not make sense in the context of Hooks alone (queries, slot types, and output messages).
The first version of Hooks made queries available in a Hook only via a query 'token', which was provided by the
componentWithQuery
function. This approach has been extended to slot types and output messages as well. With this change Hook types no longer carry around slot or output types, which cleans up type signatures for the vast majority of cases, but they are still able to support child components and sending messages once used with thecomponent
function.This includes several breaking changes, all of which are simple to adjust to the new version (no features have been removed). In summary, any Hook types that previously accepted a slot and output type will no longer have them, and any Hook functions that use these types will now use a token as their first argument. Here's the full list of changes:
Hook ps o m hooks a
is nowHook m hooks a
Hooked ps o m hooksPre hooksPost a
is nowHooked m hooksPre hooksPost a
HookM ps o m a
is nowHookM m a
- The
component
function has been updated to take as its first argument a record containing the query token, slot token, and output token that can be used to enable component features in a Hook. Any usage ofcomponent \input -> ...
can be replaced withcomponent \_ input -> ...
. - The
componentWithQuery
function has been removed, as it is now covered bycomponent
. Any usage ofcomponentWithQuery \queryToken _ -> ...
can be replaced bycomponent \{ queryToken } _ -> ...
. - The
HookM
functionraise
now takes as its first argument anOutputToken
. Any use ofHooks.raise output
can be replaced bycomponent \{ outputToken } _ -> ... Hooks.raise outputToken output
. - The
HookM
functionsquery
andqueryAll
now take as their first argument aSlotToken
. Any use ofHooks.query ...
can be replaced bycomponent \{ slotToken } _ -> ... Hooks.query slotToken ...
.
Bugfixes:
- Memo values could get out of sync with their indices in state (#11).
- Effect cleanup for useTickEffect would not run until the component finalized, running all cleanup functions together at the end (#12).
- State changes triggered by effects would not cause hooks to be re-evaluated (#20).
Other improvements:
- Tests: add automated tests for Hooks (#19).
- Tests: add continuous integration to the repository via GitHub Actions.
- Docs: update the documentation to make it clear when getting state vs. using the state from
useState
is necessary (#7). - Docs: update all public documentation to use new types and remove mention of
componentWithQuery
.
Initial release of the Halogen Hooks library.