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