Lustre Limiter is available on Hex. Add it to your project by using the gleam CLI.
gleam add lustre_limiter
This package is a port from elm-limiter written by Hayleigh, who was also a huge help in written this Gleam implementation.
In the example, the package as been imported as an alias for simplicity's sake.
import lustre_limiter as limiter
In order to use a debouncer or throttler in your Lustre application, you will need a few things.
First, your model needs to store them as following.
type Model {
Model(
// ...
debouncer: limiter.Limiter(Msg),
throttler: limiter.Limiter(Msg),
)
}
Once done, you then have to declare the relevant Lustre Msg
that will be sent to your update function when a message has been allowed through, and initialise your model using those Msg
.
pub type Msg {
// Debounce
GetInput(String)
DebounceMsg(limiter.Msg(Msg))
SearchFor(String)
// Throttle
GetClick
ThrottleMsg(limiter.Msg(Msg))
AcknowledgeClick
}
fn init(_) -> #(Model, effect.Effect(Msg)) {
#(
Model(
// ...
debouncer: limiter.debounce(DebounceMsg, 500),
throttler: limiter.throttle(ThrottleMsg, 500),
),
effect.none(),
)
}
Now comes the update
function. GetInput(String)
and GetClick
will be the two Msg
attached to our html elements, so their job is to tell the limiter that there is a new event to be process. To do this, we use limiter.push
. The first element passed to limiter.push
is the Msg
we want to receive when the limiter has completed its task and we can now modify our application accordingly, and the second argument is our limiter.
pub fn update(model: Model, msg: Msg) -> #(Model, effect.Effect(Msg)) {
case msg {
// Debounce
GetInput(value) -> {
let #(debouncer, effect) =
limiter.push(SearchFor(value), model.debouncer)
#(
Model(
// ...
),
effect,
)
}
// ...
// Throttle
GetClick -> {
let #(throttler, effect) =
limiter.push(AcknowledgeClick, model.throttler)
#(
Model(
// ...
),
effect,
)
}
}
}
Since we wrapped our Lustre Msg
in either DebounceMsg
or ThrottleMsg
when initialising our model, our update
function will receive either of these messages when limiter.push
is done processing them. This does not mean that we can update our application yet, as we first need to check if the message is allowed. To do so, we use limiter.update
as followed:
pub fn update(model: Model, msg: Msg) -> #(Model, effect.Effect(Msg)) {
case msg {
// Debounce
DebounceMsg(internal_msg) -> {
let #(debouncer, effect) = limiter.update(internal_msg, model.debouncer)
#(Model(..model, debouncer: debouncer), effect)
}
// ...
// Throttle
ThrottleMsg(internal_msg) -> {
let #(throttler, effect) = limiter.update(internal_msg, model.throttler)
#(Model(..model, throttler: throttler), effect)
}
// ...
}
}
If the message received is authorised by limiter.update
, our Lustre update
function will finally receive the Msg
type we gave to limiter.push
, either SearchFor(value)
, or AcknowledgeClick
in our case. These two can be handle any way you like.
To - for example - debounce an input field using the example above, you only have to declare an input in your view
function and set its event attribute to be event.on_input(GetInput)
.
You can run the provided example by typing the following and head to localhost:3000, or read its source code in /example.
cd example && gleam run