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

yew/
renderer.rs

1use std::cell::Cell;
2#[rustversion::since(1.81)]
3use std::panic::PanicHookInfo as PanicInfo;
4#[rustversion::before(1.81)]
5use std::panic::PanicInfo;
6use std::rc::Rc;
7
8use web_sys::Element;
9
10use crate::app_handle::AppHandle;
11use crate::html::BaseComponent;
12
13thread_local! {
14    static PANIC_HOOK_IS_SET: Cell<bool> = const { Cell::new(false) };
15}
16
17/// Set a custom panic hook.
18/// Unless a panic hook is set through this function, Yew will
19/// overwrite any existing panic hook when an application is rendered with [Renderer].
20#[cfg(feature = "csr")]
21#[allow(clippy::incompatible_msrv)]
22pub fn set_custom_panic_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + Sync + Send + 'static>) {
23    std::panic::set_hook(hook);
24    PANIC_HOOK_IS_SET.with(|hook_is_set| hook_is_set.set(true));
25}
26
27fn set_default_panic_hook() {
28    if std::thread::panicking() {
29        // very unlikely, but avoid hitting this when running parallel tests.
30        return;
31    }
32    if !PANIC_HOOK_IS_SET.with(|hook_is_set| hook_is_set.replace(true)) {
33        std::panic::set_hook(Box::new(console_error_panic_hook::hook));
34    }
35}
36
37/// The Yew Renderer.
38///
39/// This is the main entry point of a Yew application.
40#[cfg(feature = "csr")]
41#[derive(Debug)]
42#[must_use = "Renderer does nothing unless render() is called."]
43pub struct Renderer<COMP>
44where
45    COMP: BaseComponent + 'static,
46{
47    root: Element,
48    props: COMP::Properties,
49}
50
51impl<COMP> Default for Renderer<COMP>
52where
53    COMP: BaseComponent + 'static,
54    COMP::Properties: Default,
55{
56    fn default() -> Self {
57        Self::with_props(Default::default())
58    }
59}
60
61impl<COMP> Renderer<COMP>
62where
63    COMP: BaseComponent + 'static,
64    COMP::Properties: Default,
65{
66    /// Creates a [Renderer] that renders into the document body with default properties.
67    pub fn new() -> Self {
68        Self::default()
69    }
70
71    /// Creates a [Renderer] that renders into a custom root with default properties.
72    pub fn with_root(root: Element) -> Self {
73        Self::with_root_and_props(root, Default::default())
74    }
75}
76
77impl<COMP> Renderer<COMP>
78where
79    COMP: BaseComponent + 'static,
80{
81    /// Creates a [Renderer] that renders into the document body with custom properties.
82    pub fn with_props(props: COMP::Properties) -> Self {
83        Self::with_root_and_props(
84            gloo::utils::document()
85                .body()
86                .expect("no body node found")
87                .into(),
88            props,
89        )
90    }
91
92    /// Creates a [Renderer] that renders into a custom root with custom properties.
93    pub fn with_root_and_props(root: Element, props: COMP::Properties) -> Self {
94        Self { root, props }
95    }
96
97    /// Renders the application.
98    pub fn render(self) -> AppHandle<COMP> {
99        set_default_panic_hook();
100        AppHandle::<COMP>::mount_with_props(self.root, Rc::new(self.props))
101    }
102}
103
104#[cfg(feature = "hydration")]
105mod feat_hydration {
106    use super::*;
107
108    impl<COMP> Renderer<COMP>
109    where
110        COMP: BaseComponent + 'static,
111    {
112        /// Hydrates the application.
113        pub fn hydrate(self) -> AppHandle<COMP> {
114            set_default_panic_hook();
115            AppHandle::<COMP>::hydrate_with_props(self.root, Rc::new(self.props))
116        }
117    }
118}