Raxol.UI.Components.Patterns.RenderProps (Raxol v2.0.1)
View SourceRender Props pattern implementation for Raxol UI.
Render Props is a technique for sharing code between components using a prop whose value is a function. A component with a render prop takes a function that returns an element and calls it instead of implementing its own render logic.
This pattern is particularly useful for:
- Data fetching components
- Mouse/keyboard event handling
- Scroll position tracking
- Animation state management
- Form state management
Usage
# Data fetcher with render prop
%{
type: :data_provider,
attrs: %{
fetch_fn: fn -> fetch_users() end,
render: fn
%{loading: true} ->
text("Loading users...")
%{error: error} when not is_nil(error) ->
text("Error: #{error}")
%{data: users} ->
render_user_list(users)
end
}
}
# Mouse tracker with render prop
%{
type: :mouse_tracker,
attrs: %{
render: fn %{mouse_x: x, mouse_y: y} ->
text("Mouse position: (#{x}, #{y})")
end
}
}
Summary
Functions
Data provider component that fetches data and provides it via render prop.
Form state manager component that handles form state and validation via render prop.
Keyboard handler component that tracks key states and provides them via render prop.
Mouse tracker component that tracks mouse position and provides it via render prop.
Scroll tracker component that monitors scroll position and provides it via render prop.
Timer component that provides time-based state via render prop.
Functions
Data provider component that fetches data and provides it via render prop.
Props
:fetch_fn- Function that returns data (can be async):render- Function that receives%{data, loading, error, refetch}:dependencies- List of values that trigger refetch when changed:cache_key- Optional cache key for memoization
Examples
%{
type: :data_provider,
attrs: %{
fetch_fn: fn -> HTTPoison.get("/api/users") end,
dependencies: [user_id],
render: fn state ->
case state do
%{loading: true} -> loading_spinner()
%{error: error} -> error_message(error)
%{data: data} -> user_list(data)
end
end
}
}
Form state manager component that handles form state and validation via render prop.
Props
:render- Function that receives form state and handlers:initial_values- Initial form values:validation_schema- Validation rules:on_submit- Submit handler function
Examples
%{
type: :form_provider,
attrs: %{
initial_values: %{name: "", email: ""},
validation_schema: %{
name: [{:required, "Name is required"}],
email: [{:required, "Email is required"}, {:email, "Invalid email"}]
},
render: fn %{values: values, errors: errors, handle_change: change, handle_submit: submit} ->
form([
text_input(value: values.name, on_change: change.(:name)),
case errors.name do
nil -> []
error -> error_text(error)
end,
text_input(value: values.email, on_change: change.(:email)),
case errors.email do
nil -> []
error -> error_text(error)
end,
button(label: "Submit", on_click: submit)
])
end
}
}
Keyboard handler component that tracks key states and provides them via render prop.
Props
:render- Function that receives%{pressed_keys, key_combinations}:track_combinations- List of key combinations to track (e.g., [:ctrl_c, :alt_tab])
Examples
%{
type: :keyboard_handler,
attrs: %{
track_combinations: [:ctrl_c, :ctrl_v, :escape],
render: fn %{pressed_keys: keys, key_combinations: combos} ->
column([
text("Pressed keys: #{Enum.join(keys, ", ")}"),
text("Active combinations: #{Enum.join(combos, ", ")}")
])
end
}
}
Mouse tracker component that tracks mouse position and provides it via render prop.
Props
:render- Function that receives%{mouse_x, mouse_y, is_over}:track_outside- Whether to track mouse when outside component (default: false)
Examples
%{
type: :mouse_tracker,
attrs: %{
render: fn %{mouse_x: x, mouse_y: y, is_over: over} ->
column([
text("Mouse: (#{x}, #{y})"),
text("Over component: #{over}")
])
end
}
}
Scroll tracker component that monitors scroll position and provides it via render prop.
Props
:render- Function that receives%{scroll_x, scroll_y, scroll_direction, is_scrolling}:throttle_ms- Throttle scroll events (default: 16ms for 60fps)
Examples
%{
type: :scroll_tracker,
attrs: %{
throttle_ms: 50,
render: fn %{scroll_y: y, scroll_direction: dir, is_scrolling: scrolling} ->
column([
text("Scroll Y: #{y}"),
text("Direction: #{dir}"),
text("Scrolling: #{scrolling}")
])
end
}
}
Timer component that provides time-based state via render prop.
Props
:render- Function that receives timer state:interval- Update interval in milliseconds:duration- Total duration (optional):auto_start- Whether to start automatically (default: true)
Examples
%{
type: :timer,
attrs: %{
interval: 1000,
duration: 60_000, # 1 minute
render: fn %{elapsed: elapsed, remaining: remaining, percentage: pct} ->
column([
text("Elapsed: #{elapsed}ms"),
text("Remaining: #{remaining}ms"),
progress_bar(percentage: pct)
])
end
}
}