Skip to main content
This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/html/component/
mod.rs

1//! Components wrapped with context including properties, state, and link
2
3mod children;
4#[cfg(any(feature = "csr", feature = "ssr"))]
5mod lifecycle;
6mod marker;
7mod properties;
8mod scope;
9
10use std::rc::Rc;
11
12pub use children::*;
13#[cfg(feature = "csr")]
14pub(crate) use lifecycle::PendingRendered;
15pub use marker::*;
16pub use properties::*;
17#[cfg(feature = "csr")]
18pub(crate) use scope::Scoped;
19pub use scope::{AnyScope, Scope, SendAsMessage};
20
21use super::{Html, HtmlResult, IntoHtmlResult};
22
23#[cfg(feature = "hydration")]
24#[derive(Debug, Clone, Copy, PartialEq)]
25pub(crate) enum RenderMode {
26    Hydration,
27    Render,
28    #[cfg(feature = "ssr")]
29    Ssr,
30}
31
32/// The [`Component`]'s context. This contains component's [`Scope`] and props and
33/// is passed to every lifecycle method.
34#[derive(Debug)]
35pub struct Context<COMP: BaseComponent> {
36    scope: Scope<COMP>,
37    props: Rc<COMP::Properties>,
38    #[cfg(feature = "hydration")]
39    creation_mode: RenderMode,
40
41    #[cfg(feature = "hydration")]
42    prepared_state: Option<String>,
43}
44
45impl<COMP: BaseComponent> Context<COMP> {
46    /// The component scope
47    #[inline]
48    pub fn link(&self) -> &Scope<COMP> {
49        &self.scope
50    }
51
52    /// The component's props
53    #[inline]
54    pub fn props(&self) -> &COMP::Properties {
55        &self.props
56    }
57
58    #[cfg(feature = "hydration")]
59    pub(crate) fn creation_mode(&self) -> RenderMode {
60        self.creation_mode
61    }
62
63    /// The component's prepared state
64    pub fn prepared_state(&self) -> Option<&str> {
65        #[cfg(not(feature = "hydration"))]
66        let state = None;
67
68        #[cfg(feature = "hydration")]
69        let state = self.prepared_state.as_deref();
70
71        state
72    }
73}
74
75/// The common base of both function components and struct components.
76///
77/// If you are taken here by doc links, you might be looking for [`Component`] or
78/// [`#[component]`](crate::functional::component).
79///
80/// We provide a blanket implementation of this trait for every member that implements
81/// [`Component`].
82///
83/// # Warning
84///
85/// This trait may be subject to heavy changes between versions and is not intended for direct
86/// implementation.
87///
88/// You should used the [`Component`] trait or the
89/// [`#[component]`](crate::functional::component) macro to define your
90/// components.
91pub trait BaseComponent: Sized + 'static {
92    /// The Component's Message.
93    type Message: 'static;
94
95    /// The Component's Properties.
96    type Properties: Properties;
97
98    /// Creates a component.
99    fn create(ctx: &Context<Self>) -> Self;
100
101    /// Updates component's internal state.
102    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool;
103
104    /// React to changes of component properties.
105    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool;
106
107    /// Returns a component layout to be rendered.
108    fn view(&self, ctx: &Context<Self>) -> HtmlResult;
109
110    /// Notified after a layout is rendered.
111    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool);
112
113    /// Notified before a component is destroyed.
114    fn destroy(&mut self, ctx: &Context<Self>);
115
116    /// Prepares the server-side state.
117    fn prepare_state(&self) -> Option<String>;
118}
119
120/// Components are the basic building blocks of the UI in a Yew app. Each Component
121/// chooses how to display itself using received props and self-managed state.
122/// Components can be dynamic and interactive by declaring messages that are
123/// triggered and handled asynchronously. This async update mechanism is inspired by
124/// Elm and the actor model used in the Actix framework.
125pub trait Component: Sized + 'static {
126    /// Messages are used to make Components dynamic and interactive. Simple
127    /// Component's can declare their Message type to be `()`. Complex Component's
128    /// commonly use an enum to declare multiple Message types.
129    type Message: 'static;
130
131    /// The Component's properties.
132    ///
133    /// When the parent of a Component is re-rendered, it will either be re-created or
134    /// receive new properties in the context passed to the `changed` lifecycle method.
135    type Properties: Properties;
136
137    /// Called when component is created.
138    fn create(ctx: &Context<Self>) -> Self;
139
140    /// Called when a new message is sent to the component via its scope.
141    ///
142    /// Components handle messages in their `update` method and commonly use this method
143    /// to update their state and (optionally) re-render themselves.
144    ///
145    /// Returned bool indicates whether to render this Component after update.
146    ///
147    /// By default, this function will return true and thus make the component re-render.
148    #[expect(unused_variables)]
149    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
150        true
151    }
152
153    /// Called when properties passed to the component change
154    ///
155    /// Returned bool indicates whether to render this Component after changed.
156    ///
157    /// By default, this function will return true and thus make the component re-render.
158    #[expect(unused_variables)]
159    fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
160        true
161    }
162
163    /// Components define their visual layout using a JSX-style syntax through the use of the
164    /// `html!` procedural macro. The full guide to using the macro can be found in [Yew's
165    /// documentation](https://yew.rs/concepts/html).
166    ///
167    /// Note that `view()` calls do not always follow a render request from `update()` or
168    /// `changed()`. Yew may optimize some calls out to reduce virtual DOM tree generation overhead.
169    /// The `create()` call is always followed by a call to `view()`.
170    fn view(&self, ctx: &Context<Self>) -> Html;
171
172    /// The `rendered` method is called after each time a Component is rendered but
173    /// before the browser updates the page.
174    ///
175    /// Note that `rendered()` calls do not always follow a render request from `update()` or
176    /// `changed()`. Yew may optimize some calls out to reduce virtual DOM tree generation overhead.
177    /// The `create()` call is always followed by a call to `view()` and later `rendered()`.
178    #[expect(unused_variables)]
179    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {}
180
181    /// Prepares the state during server side rendering.
182    ///
183    /// This state will be sent to the client side and is available via `ctx.prepared_state()`.
184    ///
185    /// This method is only called during server-side rendering after the component has been
186    /// rendered.
187    fn prepare_state(&self) -> Option<String> {
188        None
189    }
190
191    /// Called right before a Component is unmounted.
192    #[expect(unused_variables)]
193    fn destroy(&mut self, ctx: &Context<Self>) {}
194}
195
196impl<T> BaseComponent for T
197where
198    T: Sized + Component + 'static,
199{
200    type Message = <T as Component>::Message;
201    type Properties = <T as Component>::Properties;
202
203    fn create(ctx: &Context<Self>) -> Self {
204        Component::create(ctx)
205    }
206
207    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
208        Component::update(self, ctx, msg)
209    }
210
211    fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {
212        Component::changed(self, ctx, old_props)
213    }
214
215    fn view(&self, ctx: &Context<Self>) -> HtmlResult {
216        Component::view(self, ctx).into_html_result()
217    }
218
219    fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
220        Component::rendered(self, ctx, first_render)
221    }
222
223    fn destroy(&mut self, ctx: &Context<Self>) {
224        Component::destroy(self, ctx)
225    }
226
227    fn prepare_state(&self) -> Option<String> {
228        Component::prepare_state(self)
229    }
230}
231
232#[cfg(test)]
233#[cfg(any(feature = "ssr", feature = "csr"))]
234mod tests {
235    use super::*;
236
237    struct MyCustomComponent;
238
239    impl Component for MyCustomComponent {
240        type Message = ();
241        type Properties = ();
242
243        fn create(_ctx: &Context<Self>) -> Self {
244            Self
245        }
246
247        fn view(&self, _ctx: &Context<Self>) -> Html {
248            Default::default()
249        }
250    }
251
252    #[test]
253    fn make_sure_component_update_and_changed_rerender() {
254        let mut comp = MyCustomComponent;
255        let ctx = Context {
256            scope: Scope::new(None),
257            props: Rc::new(()),
258            #[cfg(feature = "hydration")]
259            creation_mode: crate::html::RenderMode::Hydration,
260            #[cfg(feature = "hydration")]
261            prepared_state: None,
262        };
263        assert!(Component::update(&mut comp, &ctx, ()));
264        assert!(Component::changed(&mut comp, &ctx, &Rc::new(())));
265    }
266}