<web/io>
Effects, and ways to combine them. An effect describes work for the app to do. Return one from an event handler, or from update in place of a state, to run it.
let io = import <web/io>; in html.button { on.click = event: io.dispatch "increment" null; } "+"
Running effects#
Each effect has an output, which the next step in a chain receives. Chains run synchronously, rendering as they go, until an io.call effect returns a promise. Then the rest of the chain waits for it, and is dropped if the app unmounts first.
A failure skips ahead to the nearest io.catch. Failures nothing catches are logged with console.error. Values passed between steps are deeply evaluated, so a thunk that throws fails at the step that made it, not wherever it's read later.
io.dispatch#
io.dispatch type payload
Sends an action to update, which gets { type; payload; }. type is a string. Pass null for no payload. The app renders the new state, and the output is that state.
If update returns an effect instead, that runs in the dispatch's place, leaving the state as it is. The output is the effect's output.
io.call#
io.call name input
Calls the effect name the host passed to mount, with input converted to JavaScript. The output is what it returned, or what its promise resolved to. To define effects, see Host IO.
Inputs and outputs must be JSON-compatible. undefined outputs null. Errors, rejections, and missing effects fail the call, naming the effect.
io.pipe#
io.pipe value [ function ... ]
Threads value through each function in turn. When one returns an effect, the next gets its output once it runs:
io.pipe null [ (_: io.call "load" "count") (count: io.dispatch "loaded" count) ]
Returns an effect if any function returned one, or else the last function's value. io.catch handler is a step too: it handles failures of every step before it, and steps after it get its result.
io.map#
io.map function effect
Runs effect, then calls function with its output. If that returns an effect, it runs next, and its output is the chain's. Otherwise the value is.
io.map (count: io.dispatch "loaded" count) (io.call "load" "count")
io.catch#
io.catch handler effect
Runs effect. If it fails, calls handler with { message; }, and carries on from what it returns: a value, or an effect to run. Successes pass through untouched.
io.catch (error: io.dispatch "failed" error.message) (io.call "save" state)
io.all#
io.all [ effect ... ]
Runs effects in order, each after the last finishes. The output is a list of their outputs. It stops at the first failure. Values that aren't effects are outputs already.
html.form { on.submit = event: io.all [ event.preventDefault (io.dispatch "save" null) ]; }
Event effects#
Snapshots of DOM events carry event.preventDefault, an effect that calls preventDefault() on the event. It fails once the event finishes dispatching, so run it before any effect that waits on a promise. See <web/dom>.