Behaviour for native view components.
A component is a stateful Elixir process paired with a platform-native view registered by name on iOS/Android. The BEAM owns the state; the native side owns the rendering.
Lifecycle
- The parent screen declares
Dala.UI.native_view(MyComponent, id: :my_id, ...) - On first render, a
Dala.ComponentServerprocess is started andmount/2is called render/1is called to get the props map forwarded to the native factory- On subsequent renders,
update/2is called with new props from the parent - When the native view fires an event,
handle_event/3is called - After any state change,
render/1is re-called and native props are updated - When the component leaves the tree, the process is stopped and
terminate/2is called
Usage
defmodule MyApp.ChartComponent do
use Dala.Component
def mount(props, socket) do
{:ok, Dala.Socket.assign(socket, :data, props[:data])}
end
def render(assigns) do
%{data: assigns.data}
end
def handle_event("segment_tapped", %{"index" => i}, socket) do
{:noreply, Dala.Socket.assign(socket, :selected, i)}
end
endNative registration
Register the view factory at app startup:
# iOS (Swift) — strip "Elixir." prefix and replace "." with "_":
dalaNativeViewRegistry.shared.register("MyApp_ChartComponent") { props, send in
AnyView(ChartView(data: props["data"]) { index in
send("segment_tapped", ["index": index])
})
}
# Android (Kotlin):
dalaNativeViewRegistry.register("MyApp_ChartComponent") { props, send ->
ChartView(data = props["data"]) { index ->
send("segment_tapped", mapOf("index" to index))
}
}Declaration
Dala.UI.native_view(MyApp.ChartComponent, id: :revenue_chart, data: @points)The :id must be unique per screen. Duplicate ids on the same screen raise at render time.
Stateless components
If a component has no internal state, omit mount/2 and handle_info/2. The
default handle_event/3 raises for any event — add clauses for the events your
native view fires, or delegate to the parent screen by forwarding via send/2.
Summary
Functions
Walk a node tree, expanding :native_view nodes into serialisable form.
Callbacks
@callback handle_event(event :: String.t(), payload :: map(), socket :: Dala.Socket.t()) :: {:noreply, Dala.Socket.t()}
@callback handle_info(message :: term(), socket :: Dala.Socket.t()) :: {:noreply, Dala.Socket.t()}
@callback mount(props :: map(), socket :: Dala.Socket.t()) :: {:ok, Dala.Socket.t()} | {:error, term()}
@callback terminate(reason :: term(), socket :: Dala.Socket.t()) :: term()
@callback update(props :: map(), socket :: Dala.Socket.t()) :: {:ok, Dala.Socket.t()}
Functions
Walk a node tree, expanding :native_view nodes into serialisable form.
Starts or updates component processes, collects their rendered props, and
injects the NIF handle. Returns {expanded_tree, active_keys} where
active_keys is a MapSet of {id, module} pairs seen in this render —
used by the screen to stop components that have left the tree.