lifecycle.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #![allow(unused, non_upper_case_globals)]
  2. //! Tests for the lifecycle of components.
  3. use dioxus::prelude::*;
  4. use dioxus_core as dioxus;
  5. use dioxus_core::DomEdit::*;
  6. use dioxus_core::ScopeId;
  7. use dioxus_core_macro::*;
  8. use dioxus_hooks::*;
  9. use dioxus_html as dioxus_elements;
  10. use std::sync::{Arc, Mutex};
  11. mod test_logging;
  12. const IS_LOGGING_ENABLED: bool = true;
  13. type Shared<T> = Arc<Mutex<T>>;
  14. #[test]
  15. fn manual_diffing() {
  16. struct AppProps {
  17. value: Shared<&'static str>,
  18. }
  19. static App: FC<AppProps> = |cx, props| {
  20. let val = props.value.lock().unwrap();
  21. cx.render(rsx! { div { "{val}" } })
  22. };
  23. let value = Arc::new(Mutex::new("Hello"));
  24. let mut dom = VirtualDom::new_with_props(
  25. App,
  26. AppProps {
  27. value: value.clone(),
  28. },
  29. );
  30. let _ = dom.rebuild();
  31. *value.lock().unwrap() = "goodbye";
  32. let edits = dom.rebuild();
  33. log::debug!("edits: {:?}", edits);
  34. }
  35. #[test]
  36. fn events_generate() {
  37. static App: FC<()> = |cx, _| {
  38. let mut count = use_state(cx, || 0);
  39. let inner = match *count {
  40. 0 => {
  41. rsx! {
  42. div {
  43. onclick: move |_| count += 1,
  44. div {
  45. "nested"
  46. }
  47. "Click me!"
  48. }
  49. }
  50. }
  51. _ => todo!(),
  52. };
  53. cx.render(inner)
  54. };
  55. let mut dom = VirtualDom::new(App);
  56. let mut channel = dom.get_scheduler_channel();
  57. assert!(dom.has_any_work());
  58. let edits = dom.rebuild();
  59. assert_eq!(
  60. edits.edits,
  61. [
  62. CreateElement {
  63. tag: "div",
  64. root: 0,
  65. },
  66. NewEventListener {
  67. event_name: "click",
  68. scope: ScopeId(0),
  69. root: 0,
  70. },
  71. CreateElement {
  72. tag: "div",
  73. root: 1,
  74. },
  75. CreateTextNode {
  76. text: "nested",
  77. root: 2,
  78. },
  79. AppendChildren { many: 1 },
  80. CreateTextNode {
  81. text: "Click me!",
  82. root: 3,
  83. },
  84. AppendChildren { many: 2 },
  85. AppendChildren { many: 1 },
  86. ]
  87. )
  88. }
  89. #[test]
  90. fn components_generate() {
  91. static App: FC<()> = |cx, _| {
  92. let mut render_phase = use_state(cx, || 0);
  93. render_phase += 1;
  94. cx.render(match *render_phase {
  95. 0 => rsx!("Text0"),
  96. 1 => rsx!(div {}),
  97. 2 => rsx!("Text2"),
  98. 3 => rsx!(Child {}),
  99. 4 => rsx!({ None as Option<()> }),
  100. 5 => rsx!("text 3"),
  101. 6 => rsx!({ (0..2).map(|f| rsx!("text {f}")) }),
  102. 7 => rsx!(Child {}),
  103. _ => todo!(),
  104. })
  105. };
  106. static Child: FC<()> = |cx, _| {
  107. println!("running child");
  108. cx.render(rsx! {
  109. h1 {}
  110. })
  111. };
  112. let mut dom = VirtualDom::new(App);
  113. let edits = dom.rebuild();
  114. assert_eq!(
  115. edits.edits,
  116. [
  117. CreateTextNode {
  118. text: "Text0",
  119. root: 0,
  120. },
  121. AppendChildren { many: 1 },
  122. ]
  123. );
  124. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  125. assert_eq!(
  126. edits.edits,
  127. [
  128. CreateElement {
  129. tag: "div",
  130. root: 1,
  131. },
  132. ReplaceWith { root: 0, m: 1 },
  133. ]
  134. );
  135. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  136. assert_eq!(
  137. edits.edits,
  138. [
  139. CreateTextNode {
  140. text: "Text2",
  141. root: 2,
  142. },
  143. ReplaceWith { root: 1, m: 1 },
  144. ]
  145. );
  146. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  147. assert_eq!(
  148. edits.edits,
  149. [
  150. CreateElement { tag: "h1", root: 3 },
  151. ReplaceWith { root: 2, m: 1 },
  152. ]
  153. );
  154. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  155. assert_eq!(
  156. edits.edits,
  157. [CreatePlaceholder { root: 4 }, ReplaceWith { root: 3, m: 1 },]
  158. );
  159. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  160. assert_eq!(
  161. edits.edits,
  162. [
  163. CreateTextNode {
  164. text: "text 3",
  165. root: 5,
  166. },
  167. ReplaceWith { root: 4, m: 1 },
  168. ]
  169. );
  170. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  171. assert_eq!(
  172. edits.edits,
  173. [
  174. CreateTextNode {
  175. text: "text 0",
  176. root: 6,
  177. },
  178. CreateTextNode {
  179. text: "text 1",
  180. root: 7,
  181. },
  182. ReplaceWith { root: 5, m: 2 },
  183. ]
  184. );
  185. let edits = dom.hard_diff(&ScopeId(0)).unwrap();
  186. assert_eq!(
  187. edits.edits,
  188. [
  189. CreateElement { tag: "h1", root: 8 },
  190. ReplaceWith { root: 6, m: 1 },
  191. Remove { root: 7 },
  192. ]
  193. );
  194. }
  195. #[test]
  196. fn component_swap() {
  197. // simple_logger::init();
  198. static App: FC<()> = |cx, _| {
  199. let mut render_phase = use_state(cx, || 0);
  200. render_phase += 1;
  201. cx.render(match *render_phase {
  202. 0 => rsx!(
  203. div {
  204. NavBar {}
  205. Dashboard {}
  206. }
  207. ),
  208. 1 => rsx!(
  209. div {
  210. NavBar {}
  211. Results {}
  212. }
  213. ),
  214. 2 => rsx!(
  215. div {
  216. NavBar {}
  217. Dashboard {}
  218. }
  219. ),
  220. 3 => rsx!(
  221. div {
  222. NavBar {}
  223. Results {}
  224. }
  225. ),
  226. 4 => rsx!(
  227. div {
  228. NavBar {}
  229. Dashboard {}
  230. }
  231. ),
  232. _ => rsx!("blah"),
  233. })
  234. };
  235. static NavBar: FC<()> = |cx, _| {
  236. println!("running navbar");
  237. cx.render(rsx! {
  238. h1 {
  239. "NavBar"
  240. {(0..3).map(|f| rsx!(NavLink {}))}
  241. }
  242. })
  243. };
  244. static NavLink: FC<()> = |cx, _| {
  245. println!("running navlink");
  246. cx.render(rsx! {
  247. h1 {
  248. "NavLink"
  249. }
  250. })
  251. };
  252. static Dashboard: FC<()> = |cx, _| {
  253. println!("running dashboard");
  254. cx.render(rsx! {
  255. div {
  256. "dashboard"
  257. }
  258. })
  259. };
  260. static Results: FC<()> = |cx, _| {
  261. println!("running results");
  262. cx.render(rsx! {
  263. div {
  264. "results"
  265. }
  266. })
  267. };
  268. let mut dom = VirtualDom::new(App);
  269. let edits = dom.rebuild();
  270. dbg!(&edits);
  271. let edits = dom.work_with_deadline(|| false);
  272. dbg!(&edits);
  273. let edits = dom.work_with_deadline(|| false);
  274. dbg!(&edits);
  275. let edits = dom.work_with_deadline(|| false);
  276. dbg!(&edits);
  277. let edits = dom.work_with_deadline(|| false);
  278. dbg!(&edits);
  279. }