# Basics

{% hint style="warning" %}
Difficulty: Moderate

* Some basic knowledge of reactive UIs and state management is recommended.
  {% endhint %}

## What is $ui.register?

You can interact with the user interface and execute business logic via APIs provided to your plugin when you register a UI context.

```typescript
function init() {
   // This function registers the UI context for your plugin, allowing it to
   // have access to UI APIs
   $ui.register((ctx) => {
      // The 'ctx' objects contains all the APIs
   })
}
```

Unlike hooks which are called every time a specific event is triggered, the function inside `$ui.register` is called only once during the lifetime of your plugin, right after `init(),` in other words, each time your plugin is loaded.

{% hint style="info" %}
You cannot register hook handlers inside the UI callback.
{% endhint %}

## Fetch

{% hint style="info" %}
As of v3.3.0, network requests require you to whitelist domains [#network-requests](https://seanime.gitbook.io/seanime-extensions/permissions#network-requests "mention")
{% endhint %}

{% hint style="warning" %}
In the UI context, `ctx.fetch` should be used instead of simply `fetch` .
{% endhint %}

```typescript
$ui.register(async (ctx) => {
    const res = await ctx.fetch("https://jsonplaceholder.typicode.com/todos/1")
    const data = res.json()
})
```

## States

State management allows you to keep track of dynamic data within your plugin. This approach not only helps maintain a clear separation of concerns but also enables reactive programming, where UI components like the `Tray` automatically update in response to changes in states.

<pre class="language-typescript"><code class="lang-typescript">//...

<strong>const count = ctx.state(0)
</strong>
ctx.setInterval(() => {
<strong>    count.set(c => c+1)
</strong>}, 1000)

function resetCount() {
<strong>    count.set(0)
</strong>}

// Tray will update each time count changes
<strong>tray.render(() => tray.text(`Count: ${count.get()}`))
</strong></code></pre>

### Computed

```typescript
const count = ctx.state(0)
const text = ctx.computed(() => `Count is ${count.get()}`, [count])
text.get()
```

### Effects

<pre class="language-typescript"><code class="lang-typescript">// Effect registers a callback that runs each time count changes
ctx.effect(() => {
    console.log("count changed, " + count.get())
<strong>}, [count])
</strong></code></pre>

### Example

In this example, we fetch some info from an external API each time the user navigates to an anime page.

{% code title="Example" %}

```typescript
const currentMediaId = ctx.state<number | null>(null)
const fetchedData = ctx.state([])

// When the user navigates to an anime, get the media ID
ctx.screen.onNavigate((e) => {
    if (e.pathname === "/entry" && !!e.searchParams.id) {
        const id = parseInt(e.searchParams.id);
        currentMediaId.set(id);
    } else {
        currentMediaId.set(null);
    }
});

// Trigger 'ctx.screen.onNavigate' when the plugin loads 
ctx.screen.loadCurrent()

// Fetch data each time the media ID changes.
ctx.effect(async () => {
    if (!currentMediaId.get()) return
    
    const res = ctx.fetch(`https://example.com/anilistId?=${currentMediaId.get()}`)
    // Store the results
    fetchedData.set(res.json())
}, [currentMediaId])
```

{% endcode %}
