|
We built it into the framework, if you happen to be familiar with Elm, this should make sense right away, but here's how you'd write something like that using Hyperapp: import { h, app } from "hyperapp"
import { delay } from "@hyperapp/time"
const Decrement = (state) => state - 1
app({
init: 0,
view: (state) =>
h("div", {}, [
h("h1", {}, state),
h("button", {
onclick: (state/*, event*/) => [state, delay(100, Decrement)],
}, "subtract"
),
h("button", { onclick: (state) => state + 1 }, "add"),
]),
node: document.getElementById("app"),
})
See how you never actually called setTimeout as that would be a side effect.Instead, we have "controlled effects" in Hyperapp. This `delay` function doesn't even call setTimeout itself, but return an object that tells Hyperapp how. Just like how `h("button")` or `<button>` with JSX doesn't actually create a button, but an object representation of it. Finally this part: [state, delay(100, Decrement)], only placed here for convenience (as you'll usually want that in its own action) is how you tell Hyperapp to do the effect when the button is clicked. This is the same (model Cmd) continuation pattern used in Elm. |
But there is worst, the problem with the pattern [state command] is that it doesn't work well with async method, because at the time the command is called, the state which is passed alongside the command and the state maintained by Hyperapp may be different.
With your example, the issue is that Decrement may be called on a previous state and not on the actual state.
The idea of the updater is to provide the function that takes the transition function as parameter, so delay will be written that way
If you want to decrement the state after a delay using the state at that time (from the Hyperapp perspective, the event listener return undefined so you don't have to update the state at the time the event listener is called)and if you want to decrement the state using the state at the time the user click
The other benefit is that because delay() takes an updater as first argument, it's clear that the function delay does a side effect. Conceptually, the idea is that instead of trying to hide the side effect, you make it clear to the developer (more like Haskell does).