# Calling helpers from render

> A render expression may call a PURE client helper — a component `method`, a client class method, a top-level function — and render the value it returns (`Text(Twice())`). The compiler PROVES the call is safe: client-side, writes no state, invokes no effect. A call that reaches the server, writes state, or runs an effect is a precise compile error, so a render expression stays synchronous and pure by construction.

<!-- id: ui-render-calls · area: ui · stability: stable · html: https://osysharp.com/reference/ui/render-calls/ -->

## Summary        {#summary}
Render is where you turn data into what's on screen — and sometimes the value you want to show needs a small
computation. Write it as a **component `method`** (or any pure client helper) and call it right in the render
expression:

```osy syntax
component Cart() {
  live var items = LineItem.ToList();
  decimal Subtotal() => items.Sum(i => i.Price * i.Qty);   // a pure helper over component state

  render { Text(Subtotal()); }                              // call it in render — natural C#
}
```

The call runs **in the browser, synchronously**, as part of rendering — and re-runs (repainting only that slot) when a
value the helper read changes. See [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/) for the fine-grained update model.

## Signature      {#signature}
```osy syntax
render { Text(Helper(arg)) }   // Helper is a component method, a client class method, or a top-level function
```

A render call is legal **iff** it is **client-side (never suspends) ∧ writes no state ∧ invokes no effect** — the
compiler checks all three.

## Description    {#description}

### What you can call   {#allowed}
- A **component `method`** — `int Twice() => n * 2;` then `Text(Twice())`. It reads the component's own state through
  `this` implicitly, exactly as an `action` does.
- A **client class method** — `money.Formatted()` on a `class` value whose method body is client-runnable.
- A **top-level function** whose body is client-runnable — an ordinary `string Shout(string s) { … }`. You mark
  nothing: the compiler decides where it can run from what it touches, and refuses the call if the answer is the
  server.

Pure stdlib calls (`Convert.ToString`, `Enum.Label`, …) have always been render-slot material; this extends the same
door to **your own** helpers, so you don't have to hoist a one-line computation into a `live var` just to name it.

### What the compiler refuses — and why   {#refused}
A render expression must run **synchronously and purely** on the client (it can re-run many times as data changes, and
it may not block or cause side effects). So a call that breaks any of the three rules is a **compile error that names
the offending reach**:

| The call… | Error |
|---|---|
| reaches a **data read** or a **server function** | `… cannot be called from a render expression — it reaches server-side work …` |
| **writes** the component's own state | `… it assigns the component's own state (`count`) …` |
| invokes an **effect** (`Log`, `Http`, …) | `… it invokes the effect `Log.Information` …` |

The fix is always the same: move the imperative call into an `action` or `on mount`, store what it produces in state,
and render *that*. A data read is a `live var` query ([component](https://osysharp.com/reference/ui/component/)); a one-time load is [on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/).

### Why this is safe by construction   {#purity}
The fine-grained renderer re-runs a slot's expression inside a tracking effect whenever a value it read changes
([The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/)). "A render expression is pure" therefore isn't a convention you must remember — it's a compile-time
guarantee, which is what lets you call your helpers in the view without ever creating a render loop.

## Examples       {#examples}
A cart line renders a per-row subtotal via a pure helper — no `live var` needed for the one-liner:

```osy title="render-helper" test app=ui-render-calls
entity Product { string Name; decimal Price; }

[Page("/catalog")]
[Render(CSR)]
component Catalog() {
  live var products = Product.ToList();
  decimal WithTax(decimal price) => price * 1.25m;   // a pure client helper

  render {
    foreach (var p in products) {
      Text(p.Name);
      Text(WithTax(p.Price));                          // called in render — the compiler proves it pure
    }
  }
}
```

## See also       {#see-also}
- [component](https://osysharp.com/reference/ui/component/) — the `method` member, and the `live var` query you'd reach for when a value needs the server.
- [The reactivity & lifecycle model](https://osysharp.com/reference/ui/reactivity/) — the fine-grained model that makes "render is pure" a structural requirement.
- [on change](https://osysharp.com/reference/ui/on-change/) — the reactive block for pushing a value *out* of the component (the opposite direction).
- [on mount / on unmount](https://osysharp.com/reference/ui/lifecycle/) — `on mount`, for one-time imperative setup a render call may not do.
