123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- use dioxus_core::VNode;
- use dioxus_core::*;
- use dioxus_core_macro::*;
- use dioxus_html as dioxus_elements;
- use dioxus_native_core::real_dom::*;
- #[derive(Debug, Clone, PartialEq, Default)]
- struct CallCounter(u32);
- impl BubbledUpState for CallCounter {
- type Ctx = ();
- fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
- where
- I: Iterator<Item = &'a Self>,
- Self: 'a,
- {
- self.0 += 1;
- }
- }
- impl PushedDownState for CallCounter {
- type Ctx = ();
- fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {
- self.0 += 1;
- }
- }
- #[derive(Debug, Clone, PartialEq, Default)]
- struct BubbledUpStateTester(String, Vec<Box<BubbledUpStateTester>>);
- impl BubbledUpState for BubbledUpStateTester {
- type Ctx = u32;
- fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, ctx: &mut Self::Ctx)
- where
- I: Iterator<Item = &'a Self>,
- Self: 'a,
- {
- assert_eq!(*ctx, 42);
- *self = BubbledUpStateTester(
- vnode.mounted_id().to_string(),
- children.map(|c| Box::new(c.clone())).collect(),
- );
- }
- }
- #[derive(Debug, Clone, PartialEq, Default)]
- struct PushedDownStateTester(String, Option<Box<PushedDownStateTester>>);
- impl PushedDownState for PushedDownStateTester {
- type Ctx = u32;
- fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, ctx: &mut Self::Ctx) {
- assert_eq!(*ctx, 42);
- *self = PushedDownStateTester(
- vnode.mounted_id().to_string(),
- parent.map(|c| Box::new(c.clone())),
- );
- }
- }
- #[test]
- fn tree_state_initial() {
- #[allow(non_snake_case)]
- fn Base(cx: Scope) -> Element {
- rsx!(cx, div {
- p{}
- h1{}
- })
- }
- let vdom = VirtualDom::new(Base);
- let mutations = vdom.create_vnodes(rsx! {
- div {
- p{}
- h1{}
- }
- });
- let mut tree: RealDom<BubbledUpStateTester, PushedDownStateTester> = RealDom::new();
- let nodes_updated = tree.apply_mutations(vec![mutations]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut 42, &mut 42);
- let root_div = &tree[1];
- assert_eq!(root_div.up_state.0, "1");
- assert_eq!(
- root_div.up_state.1,
- vec![
- Box::new(BubbledUpStateTester("2".to_string(), Vec::new())),
- Box::new(BubbledUpStateTester("3".to_string(), Vec::new()))
- ]
- );
- assert_eq!(root_div.down_state.0, "1");
- assert_eq!(root_div.down_state.1, None);
- let child_p = &tree[2];
- assert_eq!(child_p.up_state.0, "2");
- assert_eq!(child_p.up_state.1, Vec::new());
- assert_eq!(child_p.down_state.0, "2");
- assert_eq!(
- child_p.down_state.1,
- Some(Box::new(PushedDownStateTester("1".to_string(), None)))
- );
- let child_h1 = &tree[3];
- assert_eq!(child_h1.up_state.0, "3");
- assert_eq!(child_h1.up_state.1, Vec::new());
- assert_eq!(child_h1.down_state.0, "3");
- assert_eq!(
- child_h1.down_state.1,
- Some(Box::new(PushedDownStateTester("1".to_string(), None)))
- );
- }
- #[test]
- fn tree_state_reduce_initally_called_minimally() {
- #[derive(Debug, Clone, PartialEq, Default)]
- struct CallCounter(u32);
- impl BubbledUpState for CallCounter {
- type Ctx = ();
- fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
- where
- I: Iterator<Item = &'a Self>,
- Self: 'a,
- {
- self.0 += 1;
- }
- }
- impl PushedDownState for CallCounter {
- type Ctx = ();
- fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {
- self.0 += 1;
- }
- }
- #[allow(non_snake_case)]
- fn Base(cx: Scope) -> Element {
- rsx!(cx, div {
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- })
- }
- let vdom = VirtualDom::new(Base);
- let mutations = vdom.create_vnodes(rsx! {
- div {
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- }
- });
- let mut tree: RealDom<CallCounter, CallCounter> = RealDom::new();
- let nodes_updated = tree.apply_mutations(vec![mutations]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
- tree.traverse_depth_first(|n| {
- assert_eq!(n.up_state.0, 1);
- assert_eq!(n.down_state.0, 1);
- });
- }
- #[test]
- fn tree_state_reduce_down_called_minimally_on_update() {
- #[allow(non_snake_case)]
- fn Base(cx: Scope) -> Element {
- rsx!(cx, div {
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- })
- }
- let vdom = VirtualDom::new(Base);
- let mutations = vdom.create_vnodes(rsx! {
- div {
- width: "100%",
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- }
- });
- let mut tree: RealDom<CallCounter, CallCounter> = RealDom::new();
- let nodes_updated = tree.apply_mutations(vec![mutations]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
- let nodes_updated = tree.apply_mutations(vec![Mutations {
- edits: vec![DomEdit::SetAttribute {
- root: 1,
- field: "width",
- value: "99%",
- ns: Some("style"),
- }],
- dirty_scopes: fxhash::FxHashSet::default(),
- refs: Vec::new(),
- }]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
- tree.traverse_depth_first(|n| {
- assert_eq!(n.down_state.0, 2);
- });
- }
- #[test]
- fn tree_state_reduce_up_called_minimally_on_update() {
- #[allow(non_snake_case)]
- fn Base(cx: Scope) -> Element {
- rsx!(cx, div {
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- })
- }
- let vdom = VirtualDom::new(Base);
- let mutations = vdom.create_vnodes(rsx! {
- div {
- width: "100%",
- div{
- div{
- p{}
- }
- p{
- "hello"
- }
- div{
- h1{}
- }
- p{
- "world"
- }
- }
- }
- });
- let mut tree: RealDom<CallCounter, CallCounter> = RealDom::new();
- let nodes_updated = tree.apply_mutations(vec![mutations]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
- let nodes_updated = tree.apply_mutations(vec![Mutations {
- edits: vec![DomEdit::SetAttribute {
- root: 4,
- field: "width",
- value: "99%",
- ns: Some("style"),
- }],
- dirty_scopes: fxhash::FxHashSet::default(),
- refs: Vec::new(),
- }]);
- let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
- tree.traverse_depth_first(|n| {
- assert_eq!(n.up_state.0, if n.id.0 > 4 { 1 } else { 2 });
- });
- }
|