# Ambient accessors

> VContext, VProps and VModel: read the context, props or model anywhere in a view with vcontext, vprops and vmodel.

Source: https://haskell-miso.org/docs/ambient/

As of **1.14.0**, a component's `view` takes only the `model`. The `context` and `props` are read *ambiently* instead — at the point in the tree that actually needs them — with `vcontext` and `vprops`. `vmodel` completes the trio.

These three are *accessors*, not nodes. Each wraps a function from the value to a `View`. The function is applied and the wrapper discarded whenever the enclosing `View` is built or rendered, so `VContext`, `VProps` and `VModel` never appear in the virtual DOM the runtime diffs.

## The trio

- `vcontext` — read the app-global `context`. Synonym: `withContext`.
- `vprops` — read the enclosing component's `props`. Synonym: `withProps`.
- `vmodel` — read the enclosing component's `model`. Synonym: `withModel`.

All three share one shape — a function in, a `View` out:

```haskell
vcontext :: (context -> View context props model action)
         -> View context props model action

vprops   :: (props   -> View context props model action)
         -> View context props model action

vmodel   :: (model   -> View context props model action)
         -> View context props model action
```

## Why they exist

Before 1.14.0, a view was handed all three values as arguments:

```haskell
-- before 1.14.0
view :: context -> props -> model -> View context model action
view ctx props model = ...
```

That meant every helper needing the `context` had to take it as an extra parameter, threaded down through the whole tree — even helpers that used nothing else. Now the view takes only the model, and anything deeper reaches for what it needs, where it needs it:

```haskell
-- 1.14.0
view :: model -> View Ctx props model action
view model =
  H.div_ []
    [ H.h1_ [] [ text (title model) ]
    , themeBadge          -- nothing has to pass it the context
    ]

themeBadge :: View Ctx props model action
themeBadge =
  vcontext $ \ctx ->
    H.span_ [] [ text (themeLabel (ctxTheme ctx)) ]
```

## Scope: what each one sees

Unlike `context`, which is one global value, `props` and `model` are per-component. That is why both are type parameters of `View`: the `props` a `VProps` sees is statically the `props` of the `Component` whose `view` contains it, and a mismatch is a compile-time error.

- **context** — the one live value for the whole tree; every nested component agrees on its type.
- **props** — the enclosing component's own. A child mounted with `mountWithProps` / `vcomp` sees *its* props, never its parent's.
- **model** — likewise the enclosing component's own; a mount boundary forgets the child's model type just as it forgets its props and action.

> **Note:** Accessors add no redraw logic of their own. Whether a component redraws on a `context` change is still decided solely by `useContext`; a component redraws on new `props` from its parent, and on its own `model` changing after an `update`. The accessor is simply re-resolved as part of that redraw.

## vmodel and view

The `model` is the one value the view already receives, so `vmodel` is a convenience rather than a necessity — these two are equivalent:

```haskell
view model = H.p_ [] [ text (ms (count model)) ]

view _ = vmodel $ \model ->
           H.p_ [] [ text (ms (count model)) ]
```

It earns its keep deeper in a tree, where a helper wants the model but sits several combinators away from the `view` that was handed it.

## Why not ImplicitParams or a Reader?

Both are alternatives for ambient values. `ImplicitParams` gives the same "read it where you need it" ergonomics, but is a GHC-specific extension whose constraints leak into every helper's signature. A `Reader` would work on any compiler, but forces a monadic style onto view code that is otherwise plain applicative expressions and lists. The accessors keep the `View` DSL as ordinary Haskell values: just another constructor, resolved by the runtime, with nothing to lift or thread.

## Rendering to HTML

When serialising, a bare `View` under `toHtml` is static markup with `context ~ ()`, `props ~ ()` and `model ~ ()`. A view that reads real values is rendered with `toHtmlWith`, which takes them:

```haskell
toHtmlWith
  :: context
  -> props
  -> model
  -> View context props model action
  -> ByteString

toHtmlWith ctx props model (view comp model)
```

This site's prerenderer does exactly that — there is no global context cell to seed, the value is handed to the renderer. See [HTML & prerendering](https://haskell-miso.org/docs/html-and-prerendering/).

## Try it

The [Context](https://haskell-miso.org/docs/context/) and [Props](https://haskell-miso.org/docs/props/) pages both have live demos whose views read their values through these accessors.
