[yew-devel] [RFC yew-comp] refactor: move LoadableComponent state into component implementations
Thomas Lamprecht
t.lamprecht at proxmox.com
Tue Dec 9 19:31:14 CET 2025
Am 09.12.25 um 15:36 schrieb Dietmar Maurer:
> Major Refactoring of the `LoadableComponent` system.
>
> Encapsulate component state (loading, error, view_state) into a new
> `LoadableComponentState` struct.
> Instead of `LoadableComponentMaster` managing the state externally,
> the concrete components now own their `LoadableComponentState`.
>
> - Use `impl_deref_mut_property`LoadableComponentState` struct. to implement
> Deref/DerefMut for components, allowing `LoadableComponentMaster` to
> access the state transparently.
> - `LoadableComponentContext` is now a normal yew Scope (removed custom implementation)
> - Migrate all `LoadableComponent` implementations (ACL, ACME, APT, Network,
> User/Token/TFA views, etc.) to the new pattern.
> - Use `link.custom_callback` and `link.send_custom_message` for internal
> messaging (rename is necessaray because of naming conflict with standard
s/necessaray/necessary/
> Scope function).
> - avoid useless Redraw/Datachange/Refresh messages, because `LoadableComponentMaster`
> already implements that.
Besides above typo in the commit message and another typo in the doc-comment
example (see below), this looks OK to me.
> diff --git a/src/loadable_component.rs b/src/loadable_component.rs
> index f0e28a9..43cb7a9 100644
> --- a/src/loadable_component.rs
> +++ b/src/loadable_component.rs
> @@ -1,163 +1,313 @@
> -use anyhow::Error;
> -use serde_json::Value;
> use std::future::Future;
> +use std::ops::DerefMut;
> use std::pin::Pin;
> -use yew_router::scope_ext::RouterScopeExt;
>
> +use anyhow::Error;
> use gloo_timers::callback::Timeout;
>
> +use serde_json::Value;
> use yew::html::Scope;
>
> use pwt::dom::DomVisibilityObserver;
> use pwt::prelude::*;
> -use pwt::state::NavigationContextExt;
> use pwt::widget::{AlertDialog, Column};
> use pwt::AsyncPool;
>
> +#[cfg(doc)]
> +use crate::impl_deref_mut_property;
> +#[cfg(doc)]
> +use pwt::widget::Dialog;
> +
> use crate::{TaskProgress, TaskViewer};
>
> -pub struct LoadableComponentState {
> - loading: usize,
> - last_load_error: Option<String>,
> - repeat_timespan: u32, /* 0 => no repeated loading */
> - task_base_url: Option<AttrValue>,
> -}
> +pub type LoadableComponentContext<L> = Context<LoadableComponentMaster<L>>;
> +pub type LoadableComponentScope<L> = Scope<LoadableComponentMaster<L>>;
> +
> +/// Loadable Components
> +///
> +/// - Load data using an async function [LoadableComponent::load]
> +/// - repeated load possible
> +/// - pause repeated load when component is not visible (uses [DomVisibilityObserver])
> +/// - display the loaded data [LoadableComponent::main_view]
> +/// - display an optional toolbar [LoadableComponent::toolbar]
> +/// - display any errors from failed load.
> +/// - display additional dialogs depening on [LoadableComponent::ViewState]
> +///
> +/// The [LoadableComponentScopeExt] defines available control function on the scope.
> +///
> +/// The [LoadableComponentState] provides acces to load status informations and add the ability
> +/// to spawn tasks.
> +///
> +/// ```
> +/// use proxmox_yew_comp::{LoadableComponent, LoadableComponentState, LoadableComponentContext};
> +/// // include the scope extension for (for `change_view`, `send_custom_message`, ...)
> +/// use proxmox_yew_comp::LoadableComponentScopeExt;
> +/// # use std::pin::Pin;
> +/// # use std::rc::Rc;
> +/// # use std::future::Future;
> +/// # use pwt::prelude::*;
> +/// # use proxmox_yew_comp::http_get;
> +/// # use yew::virtual_dom::{VComp, VNode, Key};
> +///
> +/// // define the component properties
> +/// #[derive(Clone, PartialEq, Properties)]
> +/// pub struct MyComponent {
> +/// key: Option<Key>,
> +/// /* add whatever you need */
> +/// };
> +///
> +/// // define your view states
> +/// #[derive(PartialEq)]
> +/// pub enum ViewState { Add, Edit }
> +///
> +/// // define the component message type
> +/// pub enum Msg { UpdateData(String) }
> +///
> +/// // define the component state
> +/// pub struct MyComponentState {
> +/// // you need to inlucde a LoadableComponentState
typo s/inlucde/include/
> +/// state: LoadableComponentState<ViewState>,
> +/// // Add any other data you need
> +/// loaded_data: Option<String>,
> +/// }
> +///
> +/// // implement DerefMut
> +/// proxmox_yew_comp::impl_deref_mut_property!(
> +/// MyComponentState,
> +/// state,
> +/// LoadableComponentState<ViewState>
> +/// );
> +///
More information about the yew-devel
mailing list