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