yew_state/component/
view.rs1use std::rc::Rc;
2
3use yew::{Component, ComponentLink, Html, Properties, ShouldRender};
4
5use crate::handle::Handle;
6use crate::{SharedState, SharedStateComponent};
7
8pub type Render<H> = Rc<dyn Fn(&H) -> Html>;
9pub type Rendered<H> = Rc<dyn Fn(&H, bool)>;
10pub type Change<H> = Rc<dyn Fn(&H, &H) -> bool>;
11
12#[derive(Properties, Clone)]
13pub struct Props<H>
14where
15 H: Handle + Clone + Default,
16{
17 #[prop_or_default]
18 handle: H,
19 pub view: Render<H>,
20 #[prop_or_default]
21 pub rendered: Option<Rendered<H>>,
22 #[prop_or_default]
23 pub change: Option<Change<H>>,
24}
25
26impl<H> SharedState for Props<H>
27where
28 H: Handle + Clone + Default,
29{
30 type Handle = H;
31
32 fn handle(&mut self) -> &mut Self::Handle {
33 &mut self.handle
34 }
35}
36
37pub enum Msg {}
38
39pub struct Model<H>
40where
41 H: Handle + Clone + Default,
42{
43 props: Props<H>,
44}
45
46impl<H> Component for Model<H>
47where
48 H: Handle + Default + Clone + 'static,
49{
50 type Message = Msg;
51 type Properties = Props<H>;
52
53 fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
54 Self { props }
55 }
56
57 fn rendered(&mut self, first_render: bool) {
58 if let Some(ref f) = self.props.rendered {
59 f(&self.props.handle, first_render)
60 }
61 }
62
63 fn update(&mut self, _msg: Self::Message) -> ShouldRender {
64 true
65 }
66
67 fn view(&self) -> Html {
68 (self.props.view)(&self.props.handle)
69 }
70
71 fn change(&mut self, props: Self::Properties) -> ShouldRender {
72 let is_eq = Rc::ptr_eq(&self.props.view, &props.view)
74 && ptr_eq(&self.props.rendered, &props.rendered)
75 && ptr_eq(&self.props.change, &props.change);
76 if !is_eq {
78 self.props.view = props.view;
79 self.props.rendered = props.rendered;
80 self.props.change = props.change;
81 }
82 let should_change = {
84 if let Some(ref f) = self.props.change {
85 f(&self.props.handle, &props.handle)
86 } else {
87 true
89 }
90 };
91 if should_change {
93 self.props.handle = props.handle;
94 }
95
96 !is_eq || should_change
97 }
98}
99
100fn ptr_eq<T: ?Sized>(a: &Option<Rc<T>>, b: &Option<Rc<T>>) -> bool {
101 a.as_ref()
102 .zip(b.as_ref())
103 .map(|(a, b)| Rc::ptr_eq(a, b))
104 .unwrap_or_default()
105}
106
107pub type StateView<H> = SharedStateComponent<Model<H>>;
108
109pub fn view<F, H>(f: F) -> Render<H>
111where
112 F: Fn(&H) -> Html + 'static,
113{
114 Rc::new(f)
115}
116
117pub fn rendered<F, H>(f: F) -> Rendered<H>
119where
120 F: Fn(&H, bool) + 'static,
121{
122 Rc::new(f)
123}
124
125pub fn change<F, H>(f: F) -> Change<H>
127where
128 F: Fn(&H, &H) -> bool + 'static,
129{
130 Rc::new(f)
131}