Skip to content
Subha Sundar Das edited this page Jul 14, 2026 · 1 revision

Hooks allow a component to remember information between renders.

Without hooks, every time RetUI redraws the screen, your component would start from scratch and lose all of its state.

Most applications only need four hooks:

  • UseState
  • UseStateKeyed
  • UseEffect
  • UseContext

RetUI also provides two keyboard hooks for building custom interactive components.


What is a Hook?

A hook is simply a function that gives your component extra capabilities.

For example:

  • Remember a value
  • React to changes
  • Share data with other components
  • Handle keyboard input

Hooks can only be called inside a component.


UseState

UseState stores a value that can change over time.

count, setCount := retui.UseState(0)

count contains the current value.

setCount updates the value.

setCount(count + 1)

Whenever you call setCount(), RetUI automatically redraws the component.


Example

func Counter() retui.Element {
    count, setCount := retui.UseState(0)

    return components.Button().
        Label(fmt.Sprintf("Count: %d", count)).
        OnPress(func() {
            setCount(count + 1)
        })
}

Every button press increases the counter.


Multiple States

A component can have more than one state.

name, setName := retui.UseState("")
age, setAge := retui.UseState(0)
active, setActive := retui.UseState(false)

Each state is independent.


UseStateKeyed

UseState stores values by the order hooks are called.

Sometimes that isn't enough.

Imagine a tree view where items appear and disappear.

▶ Documents
▶ Downloads
▶ Pictures

Each node needs its own state.

Instead of using call order, UseStateKeyed stores values using a unique key.

expanded, setExpanded :=
    retui.UseStateKeyed("node-"+id, false)

No matter how the tree changes, the correct state is always restored.

Use UseStateKeyed when:

  • Tree views
  • Dynamic lists
  • Variable forms
  • Any component created from changing data

UseEffect

UseEffect runs code when something changes.

retui.UseEffect(func() func() {
    retui.Debug("Count changed")

    return nil
}, []any{count})

The first argument is the function to run.

The second argument is a list of dependencies.

The effect only runs when one of those values changes.


Cleanup

Sometimes you need to clean something up before the effect runs again.

retui.UseEffect(func() func() {

    startWatcher()

    return func() {
        stopWatcher()
    }

}, []any{path})

Cleanup runs automatically before the effect executes again.


When should I use UseEffect?

Good examples:

  • Start a timer
  • Save data
  • Watch a file
  • Log information
  • Call an API
  • Subscribe to events

Avoid using it for values that can simply be calculated during rendering.


Context

Sometimes many components need the same information.

For example:

  • Theme
  • Language
  • Current user
  • Application settings

Passing these values through every component quickly becomes messy.

Context solves this problem.


CreateContext

Create a context once.

var ThemeContext =
    retui.CreateContext("dark")

The value "dark" is the default.


Providing a Context

Provide a value for part of your application.

ThemeContext.Provide("light", func() retui.Element {
    return Dashboard()
})

Everything inside Dashboard now receives "light".


Reading a Context

Inside any child component:

theme := retui.UseContext(ThemeContext)

Now theme contains the current value.

No matter how deeply nested the component is.


UseFocusedKeySimple

Sometimes a component wants to handle keyboard input itself.

key, ok := retui.UseFocusedKeySimple(
    retui.IsFocused("search")
)

if ok {
    switch key.Code {

    case retui.KeyEnter:
        // Handle Enter

    case retui.KeyEsc:
        // Handle Escape
    }
}

This hook only delivers keys when the component has focus.


UseFocusedKey

UseFocusedKey works like UseFocusedKeySimple but also supports focus capture.

This is useful for:

  • Modal dialogs
  • Popups
  • Menus
  • Command palettes
key, ok :=
    retui.UseFocusedKey(
        "search",
        retui.IsFocused("search"),
    )

In most applications, UseFocusedKeySimple is enough.


Rules of Hooks

Hooks are simple, but they follow one important rule.

Always call hooks in the same order.

✅ Good

count, setCount := retui.UseState(0)

theme := retui.UseContext(ThemeContext)

retui.UseEffect(...)

❌ Don't call hooks inside an if

if loggedIn {
    retui.UseState(0)
}

❌ Don't call hooks inside a loop

for _, item := range items {
    retui.UseState(false)
}

Changing the order of hooks can cause state to be assigned to the wrong component.


Which Hook Should I Use?

Hook Purpose
UseState Store a value that changes
UseStateKeyed Store state for dynamic items
UseEffect Run code when values change
CreateContext Create shared state
UseContext Read shared state
UseFocusedKeySimple Handle keyboard input for a focused component
UseFocusedKey Handle keyboard input with focus capture support

Summary

Hooks make RetUI applications interactive.

They allow components to:

  • Remember values
  • React to changes
  • Share information
  • Handle keyboard input

For most applications, you'll mainly use:

  • UseState
  • UseEffect
  • UseContext

Everything else builds on these core ideas.

Clone this wiki locally