Skip to main content

react_rs_elements/
suspense.rs

1use crate::node::{IntoNode, Node};
2use react_rs_core::resource::{Resource, ResourceState};
3use std::rc::Rc;
4
5pub struct SuspenseData {
6    pub fallback: Box<Node>,
7    pub children: Box<Node>,
8    pub loading_signal: Rc<dyn Fn() -> bool>,
9}
10
11pub struct ErrorBoundaryData {
12    pub error_fallback: Rc<dyn Fn(String) -> Node>,
13    pub children: Box<Node>,
14    pub error_signal: Rc<dyn Fn() -> Option<String>>,
15}
16
17pub fn suspense<T: Clone + 'static>(
18    resource: &Resource<T>,
19    fallback: impl IntoNode,
20    children: impl IntoNode,
21) -> Node {
22    let state = resource.state();
23    Node::Suspense(SuspenseData {
24        fallback: Box::new(fallback.into_node()),
25        children: Box::new(children.into_node()),
26        loading_signal: Rc::new(move || state.get().is_loading()),
27    })
28}
29
30pub fn error_boundary<T: Clone + 'static>(
31    resource: &Resource<T>,
32    error_fallback: impl Fn(String) -> Node + 'static,
33    children: impl IntoNode,
34) -> Node {
35    let state = resource.state();
36    Node::ErrorBoundary(ErrorBoundaryData {
37        error_fallback: Rc::new(error_fallback),
38        children: Box::new(children.into_node()),
39        error_signal: Rc::new(move || match state.get() {
40            ResourceState::Error(e) => Some(e),
41            _ => None,
42        }),
43    })
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use crate::html;
50    use react_rs_core::resource::create_resource;
51
52    #[test]
53    fn test_suspense_creates_node() {
54        let resource = create_resource::<String>();
55        let node = suspense(
56            &resource,
57            html::p().text("Loading..."),
58            html::div().text("Content"),
59        );
60        assert!(matches!(node, Node::Suspense(_)));
61    }
62
63    #[test]
64    fn test_error_boundary_creates_node() {
65        let resource = create_resource::<String>();
66        let node = error_boundary(
67            &resource,
68            |err| html::p().text(format!("Error: {}", err)).into_node(),
69            html::div().text("Content"),
70        );
71        assert!(matches!(node, Node::ErrorBoundary(_)));
72    }
73}