# `Mob.Screen.Server`
[🔗](https://github.com/genericjam/mob/blob/master/lib/mob/screen/server.ex#L1)

One process per live screen, owning that screen's socket.

Before MOB-112 a single `Mob.Screen` process held `{module, socket,
nav_history, render_mode}` and swapped the first two in place on navigation.
Every screen shared one mailbox, so a crash in any `handle_event` took down
navigation and every other screen with it — the isolation `Mob.Screen`'s
moduledoc claimed and mob#76 had to write around.

`Mob.Router` owns navigation and starts one of these per live screen. A crash
here kills this screen only; the router sees the exit, restarts it, and
re-renders.

## `self()` means what users already assume

Inside a screen callback `self()` is now the screen's own pid, not the
process registered as `:mob_screen`. Screens already wrote
`on_tap: {self(), :save}` and started tasks expecting exactly that; before,
those resolved to the one shared process, which is what let a task started by
screen A be delivered into screen B's `handle_info` with B's socket
(MOB-107).

## A restart re-mounts

A restarted screen runs `mount/3` again and loses its assigns. Persisted
screens (`use Mob.Screen, vsn: N` or `persist: true`) get their dumped state
back through `load_state/2`; everything else starts fresh. Stated rather than
implied, because it is the visible consequence of the isolation: the screen
survives, its in-memory state does not.

## Navigation is not this process's business

A user callback that sets a nav action — `push_screen/2`, `pop_screen/1`,
`switch_tab/2` — has that action handed to the owner, and this process does
**not** paint. The owner decides which screen is current and tells that
screen to paint; painting here would flash this screen's tree for a frame
before the navigation replaced it. Ordinary messages never reach the owner,
which is what keeps it off the hot path (MOB-113).

# `render_ref`

```elixir
@type render_ref() :: reference()
```

Identifies this screen to `Mob.Sender`. Unique per **screen**, not per stack.

Every screen is a live process that repaints on any message it receives,
including the ones below the top of a stack. Keyed by stack they would share
a ref, and a timer tick in a screen the user cannot see would commit its tree
over the one they can. The sender only commits the active ref.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `dispatch`

```elixir
@spec dispatch(pid(), String.t(), map()) :: {:ok, term() | nil}
```

Run a user event, returning any navigation action it produced.

# `hot_reload`

```elixir
@spec hot_reload(pid()) :: :ok
```

Repaint with the screen module's newly loaded code.

# `render`

```elixir
@spec render(pid(), atom()) :: :ok
```

Paint this screen, with the given navigation transition.

# `render_sync`

```elixir
@spec render_sync(pid(), atom()) :: :ok
```

Paint and block until the frame has been committed.

# `socket`

```elixir
@spec socket(pid()) :: Mob.Socket.t()
```

This screen's current socket.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Start a screen linked to the calling process.

`:owner` receives nav actions and the exit signal. `:ref` identifies this
screen to `Mob.Sender` and is unique per screen — see `t:render_ref/0`.

`Mob.Router` links *and* traps exits. Linking alone would make the owner die
with any screen it stopped or that crashed; trapping alone would leave every
screen orphaned when the owner died — and an orphaned persisted screen keeps
dumping to `Mob.ScreenState` under the same key as its live replacement.
Together the owner observes each exit as a message without sharing its fate,
and screens still come down with it.

# `tree`

```elixir
@spec tree(pid()) :: map()
```

Render this screen's tree, in this screen's process.

For inspection only — it does not commit anything. Running `render/1` in the
caller instead would put user code in the owner, where a raise takes down
navigation and every other screen.

---

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