Mental model

Three details that surprise people coming from Redux-in-JS: enqueue is not dispatch, FastEq can skip the whole listener set, and follow-ups run nested inside the current dispatch, not as a later tick.

run vs run(false)

Tests and scripts use run() so the effect completes. Long-lived apps (and these live docs) use run(false) and eventually Done. A completed forkDaemon can be reaped; keep the loop on a scope (forkScoped) or on the main fiber.

Mermoid.diagram(runModes)
Mermoid.diagramInteractive(runModes, initialWidth = 640)
viewport 640px

Two FastEq gates

After the handler, Conduit compares the whole model. If that says unchanged, no listener is even asked. If the model changed, each listener compares its slice to the last value it saw. A listener on _.label does not run when only _.count moved.

Mermoid.diagram(skip)
noyesequalchanged

Follow-ups are nested

ActionResult.next is dispatched before run() looks at the queue again. IncTwice that returns Inc as follow-up becomes two handler runs in one c(IncTwice) + run().

Mermoid.diagram(follow)
Mermoid.diagramInteractive(follow, initialWidth = 640)
viewport 640px