# `Atui.Fetch`
[🔗](https://github.com/iboard/atui/blob/v0.3.0/lib/atui/fetch.ex#L1)

Runs a slow thing off the UI's process and sends the answer back to a view.

`Atui.Runtime` is a single process: it reads the keyboard, runs the view
callbacks and paints the frame, one after another. Anything done *inside* a
callback is therefore done instead of drawing, and a callback that waits on
the network is a UI that has stopped — the keyboard included. A round trip
that takes a fifth of a second is felt; one to a host that has gone away
takes as long as its timeout, and the person at the keyboard cannot even
quit.

So the work happens in a process of its own and the answer arrives as an
ordinary event. Two details make that safe to do from a view:

  * The event is addressed to the view's *module* rather than to whichever
    view has focus, so an answer that lands while a popup is open still
    reaches the view that asked for it underneath.
  * The process cannot crash. Everything the function might raise, exit or
    throw is caught and handed back as `{:error, message}` — an unhandled
    exit would print a crash report onto a terminal the UI has drawn a frame
    on, which is a worse failure than whatever caused it.

## Using it

Start it in the callback that decides something is needed, and handle the
answer in `c:Atui.View.handle_event/2`:

    def mount(opts) do
      {:ok, load(%{rows: [], loading?: true, error: nil})}
    end

    def handle_key({[:ctrl], "r"}, state), do: {:ok, load(state)}

    def handle_event({:rows, {:ok, rows}}, state) do
      {:ok, %{state | rows: rows, loading?: false, error: nil}}
    end

    def handle_event({:rows, {:error, message}}, state) do
      {:ok, %{state | loading?: false, error: message}}
    end

    defp load(state) do
      Atui.Fetch.start(__MODULE__, :rows, fn -> Repo.slow_query() end)

      %{state | loading?: true}
    end

A flag in the state is what makes the first frame draw before the answer is
in, and what stops a second fetch being started while one is in flight.

# `start`

```elixir
@spec start(module(), atom(), (-&gt; term())) :: :ok
```

Runs `fun` in another process and sends `{tag, result}` to `module`'s view.

Call it from inside a view callback: it addresses the runtime the view is
running in, which is the process making the call.

`tag` is how a view tells its fetches apart, and `result` is whatever `fun`
answered — or `{:error, message}` if it could not answer at all.

---

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