Copyright | (C) 2016-2025 David M. Johnson |
---|---|
License | BSD3-style (see the file LICENSE) |
Maintainer | David M. Johnson <code@dmj.io> |
Stability | experimental |
Portability | non-portable |
Safe Haskell | None |
Language | Haskell2010 |
Miso.Effect
Description
Synopsis
- type Effect parent model action = RWS (ComponentInfo parent) [Sink action -> JSM ()] model ()
- type Sub action = Sink action -> JSM ()
- type Sink action = action -> JSM ()
- type DOMRef = JSVal
- data ComponentInfo parent = ComponentInfo {}
- type ComponentId = Int
- mkComponentInfo :: ComponentId -> DOMRef -> ComponentInfo parent
- (<#) :: model -> JSM action -> Effect parent model action
- (#>) :: JSM action -> model -> Effect parent model action
- batch :: [JSM action] -> Effect parent model action
- batch_ :: [JSM ()] -> Effect parent model action
- io :: JSM action -> Effect parent model action
- io_ :: JSM () -> Effect parent model action
- for :: Foldable f => JSM (f action) -> Effect parent model action
- issue :: action -> Effect parent model action
- withSink :: (Sink action -> JSM ()) -> Effect parent model action
- mapSub :: (a -> b) -> Sub a -> Sub b
- noop :: action -> Effect parent model action
- runEffect :: Effect parent model action -> ComponentInfo parent -> model -> (model, [Sink action -> JSM ()])
- scheduleIO :: JSM action -> Effect parent model action
- scheduleIO_ :: JSM () -> Effect parent model action
- scheduleIOFor_ :: Foldable f => JSM (f action) -> Effect parent model action
- scheduleSub :: (Sink action -> JSM ()) -> Effect parent model action
- effectSub :: model -> (Sink action -> JSM ()) -> Effect parent model action
- batchEff :: model -> [JSM action] -> Effect parent model action
- noEff :: model -> Effect parent model action
Effect
Types
type Effect parent model action = RWS (ComponentInfo parent) [Sink action -> JSM ()] model () Source #
A monad for succinctly expressing model transitions in the update
function.
Effect
is a RWS
, where the State
abstracts over manually passing the model
around. It's also a Writer
Monad
, where the accumulator is a list of scheduled
IO
actions. Multiple actions can be scheduled using tell
from the mtl
library and a single action can be scheduled using io_
.
An Effect
represents the results of an update action.
It consists of the updated model and a list of subscriptions. Each Sub
is
run in a new thread so there is no risk of accidentally blocking the
application.
Tip: use the Effect
monad in combination with the stateful
lens
operators (all operators ending in "=
"). The following example assumes
the lenses field1
, counter
and field2
are in scope and that the
LambdaCase
language extension is enabled:
myComponent = Component { update = \case MyAction1 -> do field1 .= value1 counter += 1 MyAction2 -> do field2 %= f io_ $ do putStrLn "Hello" putStrLn "World!" , ... }
type Sink action = action -> JSM () Source #
Function to asynchronously dispatch actions to the update
function.
data ComponentInfo parent Source #
This is the 'Reader r' in Effect
. Accessible via ask
. It holds
a phantom type for parent
. This is used as a witness when calling the
parent
function, and using prop
.
Constructors
ComponentInfo | |
Fields |
type ComponentId = Int Source #
Arguments
:: ComponentId | Component ID |
-> DOMRef | DOM Reference |
-> ComponentInfo parent |
Combinators
(<#) :: model -> JSM action -> Effect parent model action infixl 0 Source #
Smart constructor for an Effect
with exactly one action.
(#>) :: JSM action -> model -> Effect parent model action infixr 0 Source #
Effect
smart constructor, flipped
batch :: [JSM action] -> Effect parent model action Source #
Smart constructor for an Effect
with multiple actions.
Since: 1.9.0.0
batch_ :: [JSM ()] -> Effect parent model action Source #
Like batch
but action are discarded
Since: 1.9.0.0
io_ :: JSM () -> Effect parent model action Source #
Like io_
but doesn't cause an action to be dispatched to
the update
function.
This is handy for scheduling IO
computations where you don't care
about their results or when they complete.
Since: 1.9.0.0
issue :: action -> Effect parent model action Source #
Issue a new Action
to be processed by update
.
update :: Action -> Effect Model Action update = \case Click -> issue HelloWorld
Since: 1.9.0.0
withSink :: (Sink action -> JSM ()) -> Effect parent model action Source #
withSink
allows users to access the sink of the Component
or top-level
Component
in their application. This is useful for introducing IO
into the system.
A synonym for tell
, specialized to Effect
.
A use-case is scheduling an IO
computation which creates a 3rd-party JS
widget which has an associated callback. The callback can then call the sink
to turn events into actions. To do this without accessing a sink requires
going via a
which introduces a leaky-abstraction.Sub
scription
update FetchJSON = withSink $ \sink -> getJSON (sink . ReceivedJSON) (sink . HandleError)
Since: 1.9.0.0
noop :: action -> Effect parent model action Source #
Helper for Component
construction, when you want to ignore the update
function temporarily, or permanently.
Since: 1.9.0.0
Internal
runEffect :: Effect parent model action -> ComponentInfo parent -> model -> (model, [Sink action -> JSM ()]) Source #
MonadFail
instance for EffectCore
Internal function used to unwrap an EffectCore
Deprecated
scheduleIOFor_ :: Foldable f => JSM (f action) -> Effect parent model action Source #
Deprecated: Please use for
instead
scheduleSub :: (Sink action -> JSM ()) -> Effect parent model action Source #
Deprecated: Please use withSink
instead