diff options
Diffstat (limited to 'examples/02-interactivity/README.md')
-rw-r--r-- | examples/02-interactivity/README.md | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/examples/02-interactivity/README.md b/examples/02-interactivity/README.md new file mode 100644 index 0000000..d97f618 --- /dev/null +++ b/examples/02-interactivity/README.md @@ -0,0 +1,111 @@ +# 02 Interactivity + +In this example we show the basic structure of all Lustre applications with a +classic counter example. + +## The Model-View-Update architecture + +All Lustre applications are built around the Model-View-Update (MVU) architecture. +This is a pattern that's been popularised by the Elm programming language and +has since been adopted by many other frameworks and languages. + +MVU applications are built around three main concepts: + +- A `Model` and a function to initialise it. +- A `Msg` type and a function to update the model based on messages. +- A `View` function to render the model as a Lustre `Element`. + +These three pieces come together to form a self-contained update loop. You produce +an initial model, render it as HTML, and convert any user interactions into +messages to handle in the update function. + + ```text + +--------+ + | | + | update | + | | + +--------+ + ^ | + | | + Msg | | Model + | | + | v ++------+ +------------------------+ +| | Model | | +| init |------------------------>| Lustre Runtime | +| | | | ++------+ +------------------------+ + ^ | + | | + Msg | | Model + | | + | v + +--------+ + | | + | view | + | | + +--------+ +``` + +### Model + +The model represents the entire state of your application. For most Lustre +applications this will be a record, but for this example we're aliasing `Int` to +our `Model` type to keep things simple. + +We also need to write an `init` function that returns the initial state of our +application. It takes one argument, known as "flags" which is provided when the +application is first started. + +```gleam +fn init(initial_count: Int) -> Model { + case initial_count < 0 { + True -> 0 + False -> initial_count + } +} +``` + +Our `init` function takes a starting count, but ensures it cannot be below `0`. + +### Update + +In many other frameworks, it's common to update state directly in an event handler. +MVU applications take a different approach: instead of state updates being scattered +around your codebase, they are handled in a single `update` function. + +To achieve this, we define a `Msg` type that represents all the different kinds of +messages our application can receive. If you're familiar with Erlang this approach +to state management will be familiar to you. If you're coming from a JavaScript +background, this approach is most-similar to state management solutions like Redux +or Vuex. + +```gleam +pub opaque type Msg { + Incr + Decr +} +``` + +This approach means it is easy to quickly get an idea of all the ways your app +can change state, and makes it easy to add new state changes over time. By pattern +matching on an incoming message in our `update` function, we can lean on Gleam's +_exhaustiveness checking_ to ensure we handle all possible messages. + +### View + + + +```gleam +fn view(model: Model) -> Element(Msg) { + ... +} +``` + + +## Creating a dynamic Lustre application + +In the previous example we used the `lustre.element` function to construct a +static Lustre app. To construct a simple interactive app we can use `lustre.simple` +instead. From now on we'll see that all the different ways to construct a Lustre +application all take the same three `init`, `update`, and `view` functions. |