# `Drafter.Runtime.Reducer`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/runtime/reducer.ex#L1)

Elm-style reducer runtime backend.

An app using this backend defines `init/1` (initial state), `update/2`
(`msg, state -> new_state`), and `render/1`. The loop's input events, named
callbacks, timers, and out-of-band messages are all delivered to `update/2`:

  * raw input events arrive as their event tuple, e.g. `{:key, :q}`
  * named callbacks arrive as `{name, data}`
  * fired timers arrive as `{:timer, timer_id}`

`update/2` returns the new state, or `{:stop, reason}` to quit. Render is skipped when it
returns a state value-equal to the previous one.

An app that does not define `update/2` falls back to the `Callback` backend.

# `handle_input`

```elixir
@spec handle_input(module(), term(), term()) ::
  {:ok, term()} | {:noreply, term()} | {:stop, term()} | term()
```

Passes the raw event tuple to the app's `update/2`.

Returns `{:noreply, state}` when `update/2` returns a state equal to the one passed
in, `{:stop, reason}` unchanged, and `{:ok, new_state}` otherwise. Apps without an
`update/2` fall through to `Drafter.Runtime.Callback.handle_input/3`.

# `handle_message`

```elixir
@spec handle_message(module(), atom(), term(), term()) ::
  {:ok, term()} | {:noreply, term()} | {:stop, term()} | term()
```

Passes a named callback to the app's `update/2` as `{name, data}`.

Result shapes match `handle_input/3`. Apps without an `update/2` fall through to
`Drafter.Runtime.Callback.handle_message/4`.

# `mount`

```elixir
@spec mount(module(), map()) :: term()
```

Calls the app's `init/1`, falling back to `Callback.mount/2` when it defines none.

# `on_message`

```elixir
@spec on_message(module(), term(), term()) :: term()
```

Passes an out-of-band process message to the app's `update/2` verbatim.

# `ready`

```elixir
@spec ready(module(), term()) :: term()
```

Delegates to `Drafter.Runtime.Callback.ready/2`.

# `refresh_rate`

```elixir
@spec refresh_rate(module()) :: Drafter.Runtime.refresh_rate()
```

Delegates to `Drafter.Runtime.Callback.refresh_rate/1`.

# `scroll_active`

```elixir
@spec scroll_active(module(), term()) :: term()
```

Delegates to `Drafter.Runtime.Callback.scroll_active/2`.

# `scroll_idle`

```elixir
@spec scroll_idle(module(), term()) :: term()
```

Delegates to `Drafter.Runtime.Callback.scroll_idle/2`.

# `timer`

```elixir
@spec timer(module(), term(), term()) :: term()
```

Passes a fired timer to the app's `update/2` as `{:timer, timer_id}`.

Returns whatever `update/2` returns, without the equality check applied by
`handle_input/3`.

# `unmount`

```elixir
@spec unmount(module(), term()) :: :ok
```

Delegates to `Drafter.Runtime.Callback.unmount/2`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
