Skip to content

Hooks

Hook primitives for @component functions: state, effects, memoization, context, and refs. Hooks must be called at the top level of a component (not inside conditionals or loops) so they can be matched to the same slot across renders.

Hook primitives for function components.

Provides React-like hooks for managing state, effects, memoization, context, and navigation within function components decorated with component. Hooks must be called at the top level of a component (not inside conditionals or loops) so they map to the same slot across renders.

Effects are queued during the render phase and flushed after the reconciler commits native-view mutations. This ordering guarantees that effect callbacks can safely measure layout or interact with the committed native tree.

Example
import pythonnative as pn

@pn.component
def Counter(initial=0):
    count, set_count = pn.use_state(initial)
    return pn.Column(
        pn.Text(f"Count: {count}"),
        pn.Button("+", on_click=lambda: set_count(count + 1)),
    )

Classes:

Name Description
HookState

Per-instance storage for one component's hooks.

QueryResult

Snapshot of a use_query subscription.

MutationState

Snapshot of a use_mutation subscription.

MutationCall

Awaitable handle returned by a mutator trigger.

Context

Container for a value shared across a subtree.

NavigationHandle

Handle returned by use_navigation.

Functions:

Name Description
batch_updates

Coalesce multiple state updates into a single re-render.

use_state

Return (value, setter) for component-local state.

use_reducer

Return (state, dispatch) for reducer-based state management.

use_effect

Schedule a side effect to run after the native commit.

use_memo

Return a memoized value that is recomputed only when deps change.

use_callback

Return a stable reference to callback, refreshed when deps change.

use_ref

Return a mutable ref dict {"current": initial} that persists across renders.

use_async_effect

Schedule an async effect that's cancelled on re-run / unmount.

use_query

Subscribe to an async fetcher and re-render when its result changes.

use_mutation

Wrap an async mutator with loading/error state and a trigger.

use_window_dimensions

Return the current viewport size and re-render when it changes.

use_safe_area_insets

Return the current safe-area insets and re-render on change.

use_keyboard_height

Return the on-screen keyboard height (or 0) and re-render on change.

create_context

Create a new context with an optional default value.

use_context

Read the current value of context from the nearest Provider.

Provider

Provide value for context to all descendants of children.

memo

Skip a function component's render when its props haven't changed.

use_navigation

Return a NavigationHandle for the screen.

component

Mark a function as a PythonNative component.

HookState

HookState()

Per-instance storage for one component's hooks.

Each @component instance owns one HookState. Hooks are matched to slots by call order, so they must always be called in the same order across renders. Effects scheduled during render are deferred into _pending_effects and flushed after the reconciler commits native mutations, which guarantees effect callbacks can safely interact with the committed native tree.

Attributes:

Name Type Description
states List[Any]

One entry per use_state / use_reducer call.

effects List[Tuple[Any, Any]]

One (deps, cleanup) tuple per use_effect call.

memos List[Tuple[Any, Any]]

One (deps, value) tuple per use_memo / use_callback.

refs List[dict]

One mutable dict per use_ref call.

Methods:

Name Description
reset_index

Reset every per-hook cursor to 0.

flush_pending_effects

Run effects queued during render, after native commit.

cleanup_all_effects

Run every outstanding cleanup function, then clear state.

reset_index

reset_index() -> None

Reset every per-hook cursor to 0.

Called by the reconciler at the start of every render pass so the next render reads slots in the same order they were written.

flush_pending_effects

flush_pending_effects() -> None

Run effects queued during render, after native commit.

For each pending effect, the previous cleanup is invoked first (if any), then the new effect callback. The new return value becomes the next cleanup.

cleanup_all_effects

cleanup_all_effects() -> None

Run every outstanding cleanup function, then clear state.

Called when the component instance is unmounted by the reconciler.

QueryResult dataclass

QueryResult(data: Optional[T] = None, loading: bool = True, error: Optional[BaseException] = None, refetch: Callable[[], None] = lambda: None)

Bases: Generic[T]

Snapshot of a use_query subscription.

Attributes:

Name Type Description
data Optional[T]

The most recent successful result, or the initial value before the first fetch completes.

loading bool

True while a fetch is in flight (including the initial fetch and any refetches).

error Optional[BaseException]

The exception raised by the most recent failed fetch, or None if no fetch has failed since the last success.

refetch Callable[[], None]

A zero-arg callable that triggers a refetch. Stable across renders.

MutationState dataclass

MutationState(data: Optional[T] = None, loading: bool = False, error: Optional[BaseException] = None)

Bases: Generic[T]

Snapshot of a use_mutation subscription.

Attributes:

Name Type Description
data Optional[T]

The most recent successful return value of the mutator, or None if no mutation has succeeded yet.

loading bool

True while a mutation is in flight.

error Optional[BaseException]

The exception raised by the most recent failed mutation, or None.

MutationCall

MutationCall(future: Any)

Bases: Generic[T]

Awaitable handle returned by a mutator trigger.

Returned by the second element of the use_mutation tuple. Awaiting the handle resolves to the mutator's return value (or re-raises its exception); discarding the handle is safe — Python won't warn about an unawaited coroutine because this is a plain object.

Example
# Fire-and-forget:
save_button.on_click = lambda: mutate(post)

# Or await for the result:
async def submit():
    try:
        created = await mutate(post)
    except ApiError as exc:
        await pn.Alert.show(title="Save failed", message=str(exc))

Methods:

Name Description
cancel

Cancel the underlying mutation. Returns whether cancellation succeeded.

done

Whether the underlying mutation has finished.

cancel

cancel() -> bool

Cancel the underlying mutation. Returns whether cancellation succeeded.

done

done() -> bool

Whether the underlying mutation has finished.

Context

Context(default: Any = None)

Container for a value shared across a subtree.

Created by create_context; consumed via use_context. Use Provider to set the value for a subtree.

Attributes:

Name Type Description
default

The value returned when no Provider ancestor exists.

NavigationHandle

NavigationHandle(host: Any)

Handle returned by use_navigation.

Wraps the host's push/pop primitives so screens can navigate without knowing the underlying native navigation stack. The typical user-facing surface is the declarative handle returned by a Stack — this class is the lower-level fallback used when no navigator is rendered (and as the bridge that declarative navigators delegate to when they need to push real native screens).

Example
import pythonnative as pn

@pn.component
def HomeScreen():
    nav = pn.use_navigation()
    return pn.Button(
        "Open Detail",
        on_click=lambda: nav.navigate("Detail", {"id": 42}),
    )

Methods:

Name Description
navigate

Push component onto the navigation stack.

go_back

Pop the current screen and return to the previous one.

get_params

Return the params dict passed to this screen.

navigate

navigate(component: Any, params: Optional[Dict[str, Any]] = None) -> None

Push component onto the navigation stack.

Parameters:

Name Type Description Default
component Any

A @component function or a dotted Python path (e.g. "app.detail.DetailScreen"). When a Stack navigator is the root of the app, prefer the declarative nav.navigate("Detail", params) form returned by use_navigation() (it pushes by route name and the host re-uses its own App component).

required
params Optional[Dict[str, Any]]

Optional dict of arguments serialized into the target screen.

None

go_back

go_back() -> None

Pop the current screen and return to the previous one.

get_params

get_params() -> Dict[str, Any]

Return the params dict passed to this screen.

Returns:

Type Description
Dict[str, Any]

The dict supplied by the caller's

Dict[str, Any]
Dict[str, Any]

call, or an empty dict if none was supplied.

batch_updates

batch_updates() -> Generator[None, None, None]

Coalesce multiple state updates into a single re-render.

State setters called inside the with block defer their re-render trigger until the block exits, so any number of set_* calls produce at most one render pass.

Yields:

Type Description
None

None. The block executes normally; deferred renders fire on

None

exit.

Example
import pythonnative as pn

with pn.batch_updates():
    set_count(1)
    set_name("hello")

use_state

use_state(initial: Any = None) -> Tuple[Any, Callable]

Return (value, setter) for component-local state.

State persists across re-renders of the same component instance. The setter accepts a value or a current -> new callable; calling it with an unchanged value is a no-op (no re-render).

Parameters:

Name Type Description Default
initial Any

Initial state value. If callable, it is invoked once on the first render (lazy initialization).

None

Returns:

Type Description
Any

A 2-tuple (value, setter) where value is the current

Callable

state and setter updates it (and triggers a re-render).

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn

@pn.component
def Counter():
    count, set_count = pn.use_state(0)
    return pn.Button(
        f"Count: {count}",
        on_click=lambda: set_count(count + 1),
    )

use_reducer

use_reducer(reducer: Callable[[Any, Any], Any], initial_state: Any) -> Tuple[Any, Callable]

Return (state, dispatch) for reducer-based state management.

A reducer is a pure function that takes the current state and an action and returns the next state. Use it instead of use_state when state transitions are complex enough that centralizing them in one function aids readability and testing.

Parameters:

Name Type Description Default
reducer Callable[[Any, Any], Any]

reducer(current_state, action) -> new_state. The component re-renders only when reducer returns a value different from the current state.

required
initial_state Any

Initial state value, or a callable invoked once on the first render.

required

Returns:

Type Description
Any

A 2-tuple (state, dispatch) where dispatch runs the

Callable

reducer with the supplied action.

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn

def reducer(state, action):
    if action == "increment":
        return state + 1
    if action == "reset":
        return 0
    return state

@pn.component
def Counter():
    count, dispatch = pn.use_reducer(reducer, 0)
    return pn.Row(
        pn.Button("+", on_click=lambda: dispatch("increment")),
        pn.Button("Reset", on_click=lambda: dispatch("reset")),
    )

use_effect

use_effect(effect: Callable, deps: Optional[list] = None) -> None

Schedule a side effect to run after the native commit.

Effects are queued during the render pass and flushed once the reconciler has finished applying all native-view mutations, which means effect callbacks can safely measure layout or interact with committed native views.

The deps argument controls when the effect re-runs:

  • None: every render.
  • []: mount only.
  • [a, b]: when a or b change (compared by identity, then ==).

effect may return a cleanup callable; the previous cleanup runs before the next effect (and on unmount).

Parameters:

Name Type Description Default
effect Callable

A zero-arg callable invoked after commit. Optionally returns a cleanup callable.

required
deps Optional[list]

Dependency list, or None to run on every render.

None

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn

@pn.component
def Timer():
    seconds, set_seconds = pn.use_state(0)

    def tick():
        import threading
        t = threading.Timer(1.0, lambda: set_seconds(seconds + 1))
        t.start()
        return t.cancel

    pn.use_effect(tick, [seconds])
    return pn.Text(f"Elapsed: {seconds}s")

use_memo

use_memo(factory: Callable[[], T], deps: list) -> T

Return a memoized value that is recomputed only when deps change.

Use this for expensive computations whose inputs change rarely. For cheap computations, plain inline code is faster (memoization itself has overhead).

Parameters:

Name Type Description Default
factory Callable[[], T]

Zero-arg callable returning the value.

required
deps list

Dependency list. The value is recomputed when any element differs from the previous render.

required

Returns:

Type Description
T

The cached or freshly computed value.

Raises:

Type Description
RuntimeError

If called outside a @component function.

use_callback

use_callback(callback: Callable, deps: list) -> Callable

Return a stable reference to callback, refreshed when deps change.

Equivalent to use_memo(lambda: callback, deps). Useful when passing a function as a prop to a memoized child component, so the child doesn't see a fresh function identity on every render.

Parameters:

Name Type Description Default
callback Callable

The callable to memoize.

required
deps list

Dependency list controlling when the reference refreshes.

required

Returns:

Type Description
Callable

A callable with stable identity across renders (until deps change).

use_ref

use_ref(initial: Any = None) -> dict

Return a mutable ref dict {"current": initial} that persists across renders.

Refs are useful for storing values that must survive renders without triggering them: timers, last-seen values, native handles, and so on.

The current key is also populated by the reconciler with the underlying native view (UIView on iOS, android.view.View on Android) when the ref is passed via the ref= prop on a built-in element. This is how Animated.View obtains a handle to the native view it animates without going through the reconciler.

Parameters:

Name Type Description Default
initial Any

Value placed at ref["current"] on first render.

None

Returns:

Type Description
dict

A dict with a single "current" key. Mutations to the dict do

dict

not trigger re-renders.

Raises:

Type Description
RuntimeError

If called outside a @component function.

use_async_effect

use_async_effect(effect: Callable[[], Awaitable[None]], deps: Optional[list] = None) -> None

Schedule an async effect that's cancelled on re-run / unmount.

Like use_effect but takes an async def (or any zero-arg callable returning an awaitable). The coroutine is scheduled on the framework runtime via run_async after the native commit. When deps change (or the component unmounts), the in-flight future is cancelled.

Parameters:

Name Type Description Default
effect Callable[[], Awaitable[None]]

A zero-arg callable returning an awaitable. Typically an async def defined inside the component.

required
deps Optional[list]

Dependency list, or None to re-run on every render.

None

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn


@pn.component
def Posts(user_id):
    posts, set_posts = pn.use_state([])

    async def load():
        set_posts(await api.get_posts(user_id))

    pn.use_async_effect(load, [user_id])
    return pn.FlatList(posts, render_item=...)

use_query

use_query(fetcher: Callable[[], Awaitable[T]], deps: Optional[list] = None, *, initial: Optional[T] = None) -> QueryResult[T]

Subscribe to an async fetcher and re-render when its result changes.

The fetcher is called on mount and any time deps change, with cancellation propagated when the component unmounts mid-fetch.

Parameters:

Name Type Description Default
fetcher Callable[[], Awaitable[T]]

Zero-arg async callable that resolves to the current data.

required
deps Optional[list]

Dependency list — refetches whenever any entry changes.

None
initial Optional[T]

Optional starting value for data before the first fetch completes.

None

Returns:

Type Description
QueryResult[T]

A frozen QueryResult with

QueryResult[T]

data / loading / error / refetch.

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn


@pn.component
def UserCard(user_id):
    q = pn.use_query(lambda: api.get_user(user_id), [user_id])
    if q.loading:
        return pn.Text("Loading…")
    if q.error:
        return pn.Text(f"Error: {q.error}")
    return pn.Text(q.data["name"])

use_mutation

use_mutation(mutator: Callable[..., Awaitable[T]]) -> Tuple[MutationState[T], Callable[..., MutationCall[T]]]

Wrap an async mutator with loading/error state and a trigger.

Returns (state, mutate). Call mutate(*args, **kwargs) to invoke the mutator; state reflects loading/error/data and re-renders on each transition. mutate returns a MutationCall you can await for the result, or discard for fire-and-forget.

Parameters:

Name Type Description Default
mutator Callable[..., Awaitable[T]]

An async callable that performs the side effect and returns the resulting data.

required

Returns:

Type Description
Tuple[MutationState[T], Callable[..., MutationCall[T]]]

A 2-tuple (state, mutate).

Example
import pythonnative as pn


@pn.component
def NewPostForm():
    state, save = pn.use_mutation(api.create_post)

    return pn.Column(
        pn.Button("Save", on_click=lambda: save(post)),
        pn.Text("Saving…") if state.loading else pn.Text(""),
        pn.Text(str(state.error)) if state.error else pn.Text(""),
    )

use_window_dimensions

use_window_dimensions() -> Dict[str, float]

Return the current viewport size and re-render when it changes.

Equivalent to React Native's useWindowDimensions. The values are pushed by the screen host whenever the platform reports a new size (initial layout, rotation, multitasking split-view).

Returns:

Type Description
Dict[str, float]

A dict with "width" and "height" floats in layout

Dict[str, float]

units (pt on iOS, dp on Android). Both are 0.0 until the

Dict[str, float]

screen host has run its first layout pass.

Raises:

Type Description
RuntimeError

If called outside a @component function.

Example
import pythonnative as pn

@pn.component
def MyView():
    dims = pn.use_window_dimensions()
    return pn.Text(f"{dims['width']:.0f} x {dims['height']:.0f}")

use_safe_area_insets

use_safe_area_insets() -> Dict[str, float]

Return the current safe-area insets and re-render on change.

Mirrors react-native-safe-area-context's useSafeAreaInsets.

Returns:

Type Description
Dict[str, float]

A dict with "top", "bottom", "left", and "right"

Dict[str, float]

floats in layout units (pt on iOS, dp on Android).

Raises:

Type Description
RuntimeError

If called outside a @component function.

use_keyboard_height

use_keyboard_height() -> float

Return the on-screen keyboard height (or 0) and re-render on change.

Useful for custom layout that needs to react to keyboard show/hide events. Most apps should use KeyboardAvoidingView instead of reading this directly.

Raises:

Type Description
RuntimeError

If called outside a @component function.

create_context

create_context(default: Any = None) -> Context

Create a new context with an optional default value.

Parameters:

Name Type Description Default
default Any

Returned by use_context when there is no enclosing Provider.

None

Returns:

Type Description
Context

A fresh Context instance.

Example
import pythonnative as pn

ThemeContext = pn.create_context({"primary": "#007AFF"})

use_context

use_context(context: Context) -> Any

Read the current value of context from the nearest Provider.

If no enclosing Provider exists, returns the context's default.

Parameters:

Name Type Description Default
context Context

The Context to read from.

required

Returns:

Type Description
Any

The current value for context.

Raises:

Type Description
RuntimeError

If called outside a @component function.

Provider

Provider(context: Context, value: Any, *children: Element) -> Element

Provide value for context to all descendants of children.

Accepts any number of children (varargs). Multiple children are grouped under an internal Fragment so they all share the same provided value without an extra wrapping native view.

Parameters:

Name Type Description Default
context Context

The Context to set.

required
value Any

Value made available to descendants via use_context.

required
*children Element

Subtree(s) under which the provider applies.

()

Returns:

Type Description
Element

An Element that the reconciler treats

Element

as a context boundary.

Example
import pythonnative as pn

ThemeContext = pn.create_context({"primary": "#007AFF"})

@pn.component
def App():
    return pn.Provider(
        ThemeContext,
        {"primary": "#FF0000"},
        Header(),
        Body(),
    )

memo

memo(component_fn: Callable[..., Element]) -> Callable[..., Element]

Skip a function component's render when its props haven't changed.

Decorate a @component-wrapped function to opt into shallow-prop memoization. When the reconciler re-renders the parent tree, a memoized child is skipped (its previously-rendered subtree is reused) iff:

  • Its props are shallowly equal to the previous render's props (callables compared by identity, scalars by ==).
  • None of its internal use_state / use_reducer setters fired since the last render.

Pair with use_callback when passing callbacks as props, otherwise a fresh closure will defeat the memo.

Parameters:

Name Type Description Default
component_fn Callable[..., Element]

A function previously decorated with component.

required

Returns:

Type Description
Callable[..., Element]

The same function, marked for memoization.

Example
import pythonnative as pn

@pn.memo
@pn.component
def ExpensiveRow(label: str):
    ...

use_navigation

use_navigation() -> NavigationHandle

Return a NavigationHandle for the screen.

Returns:

Type Description
NavigationHandle

The handle bound to the current screen's host.

Raises:

Type Description
RuntimeError

If called outside a component rendered via create_screen.

component

component(func: Callable) -> Callable[..., Element]

Mark a function as a PythonNative component.

The decorated function may use hooks (use_state, use_effect, etc.) and returns an Element tree. Each call site creates an independent component instance with its own hook state.

Positional arguments are mapped onto the function's positional parameters. If the function declares *args, positional arguments instead become the special children prop.

Parameters:

Name Type Description Default
func Callable

The function to wrap.

required

Returns:

Type Description
Callable[..., Element]

A wrapper that, when called, returns an Element whose type

Callable[..., Element]

is func itself.

Example
import pythonnative as pn

@pn.component
def Greeting(name: str = "World"):
    return pn.Text(f"Hello, {name}!")

Async hooks

For coroutines and data-driven UI, PythonNative ships dedicated async-aware hooks layered on top of use_state / use_effect:

See the Async + data guide for a complete walkthrough.

Platform-metric hooks

These hooks subscribe to values published by pythonnative.platform_metrics and re-render the component when they change. The screen host is the only code that updates the underlying values; user code consumes them.

For most apps the dedicated KeyboardAvoidingView component is preferable to consuming use_keyboard_height directly.

Next steps