walkthrough_readme.html 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. <!DOCTYPE HTML>
  2. <html lang="en" class="sidebar-visible no-js light">
  3. <head>
  4. <!-- Book generated using mdBook -->
  5. <meta charset="UTF-8">
  6. <title>Walkthrough of Internals</title>
  7. <!-- Custom HTML head -->
  8. <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  9. <meta name="description" content="">
  10. <meta name="viewport" content="width=device-width, initial-scale=1">
  11. <meta name="theme-color" content="#ffffff" />
  12. <link rel="icon" href="../favicon.svg">
  13. <link rel="shortcut icon" href="../favicon.png">
  14. <link rel="stylesheet" href="../css/variables.css">
  15. <link rel="stylesheet" href="../css/general.css">
  16. <link rel="stylesheet" href="../css/chrome.css">
  17. <link rel="stylesheet" href="../css/print.css" media="print">
  18. <!-- Fonts -->
  19. <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
  20. <link rel="stylesheet" href="../fonts/fonts.css">
  21. <!-- Highlight.js Stylesheets -->
  22. <link rel="stylesheet" href="../highlight.css">
  23. <link rel="stylesheet" href="../tomorrow-night.css">
  24. <link rel="stylesheet" href="../ayu-highlight.css">
  25. <!-- Custom theme stylesheets -->
  26. <!-- MathJax -->
  27. <script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  28. </head>
  29. <body>
  30. <!-- Provide site root to javascript -->
  31. <script type="text/javascript">
  32. var path_to_root = "../";
  33. var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
  34. </script>
  35. <!-- Work around some values being stored in localStorage wrapped in quotes -->
  36. <script type="text/javascript">
  37. try {
  38. var theme = localStorage.getItem('mdbook-theme');
  39. var sidebar = localStorage.getItem('mdbook-sidebar');
  40. if (theme.startsWith('"') && theme.endsWith('"')) {
  41. localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
  42. }
  43. if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
  44. localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
  45. }
  46. } catch (e) { }
  47. </script>
  48. <!-- Set the theme before any content is loaded, prevents flash -->
  49. <script type="text/javascript">
  50. var theme;
  51. try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
  52. if (theme === null || theme === undefined) { theme = default_theme; }
  53. var html = document.querySelector('html');
  54. html.classList.remove('no-js')
  55. html.classList.remove('light')
  56. html.classList.add(theme);
  57. html.classList.add('js');
  58. </script>
  59. <!-- Hide / unhide sidebar before it is displayed -->
  60. <script type="text/javascript">
  61. var html = document.querySelector('html');
  62. var sidebar = 'hidden';
  63. if (document.body.clientWidth >= 1080) {
  64. try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
  65. sidebar = sidebar || 'visible';
  66. }
  67. html.classList.remove('sidebar-visible');
  68. html.classList.add("sidebar-" + sidebar);
  69. </script>
  70. <nav id="sidebar" class="sidebar" aria-label="Table of contents">
  71. <div class="sidebar-scrollbox">
  72. <ol class="chapter"><li class="chapter-item expanded affix "><a href="../index.html">Introduction</a></li><li class="chapter-item expanded "><a href="../getting_started/index.html"><strong aria-hidden="true">1.</strong> Getting Started</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../getting_started/desktop.html"><strong aria-hidden="true">1.1.</strong> Desktop</a></li><li class="chapter-item expanded "><a href="../getting_started/web.html"><strong aria-hidden="true">1.2.</strong> Web</a></li><li class="chapter-item expanded "><a href="../getting_started/ssr.html"><strong aria-hidden="true">1.3.</strong> Server-Side Rendering</a></li><li class="chapter-item expanded "><a href="../getting_started/fullstack.html"><strong aria-hidden="true">1.4.</strong> Fullstack</a></li><li class="chapter-item expanded "><a href="../getting_started/liveview.html"><strong aria-hidden="true">1.5.</strong> Liveview</a></li><li class="chapter-item expanded "><a href="../getting_started/tui.html"><strong aria-hidden="true">1.6.</strong> Terminal UI</a></li><li class="chapter-item expanded "><a href="../getting_started/mobile.html"><strong aria-hidden="true">1.7.</strong> Mobile</a></li><li class="chapter-item expanded "><a href="../getting_started/hot_reload.html"><strong aria-hidden="true">1.8.</strong> Hot Reloading</a></li></ol></li><li class="chapter-item expanded "><a href="../describing_ui/index.html"><strong aria-hidden="true">2.</strong> Describing the UI</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../describing_ui/special_attributes.html"><strong aria-hidden="true">2.1.</strong> Special Attributes</a></li><li class="chapter-item expanded "><a href="../describing_ui/components.html"><strong aria-hidden="true">2.2.</strong> Components</a></li><li class="chapter-item expanded "><a href="../describing_ui/component_props.html"><strong aria-hidden="true">2.3.</strong> Props</a></li><li class="chapter-item expanded "><a href="../describing_ui/component_children.html"><strong aria-hidden="true">2.4.</strong> Component Children</a></li></ol></li><li class="chapter-item expanded "><a href="../interactivity/index.html"><strong aria-hidden="true">3.</strong> Interactivity</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../interactivity/event_handlers.html"><strong aria-hidden="true">3.1.</strong> Event Listeners</a></li><li class="chapter-item expanded "><a href="../interactivity/hooks.html"><strong aria-hidden="true">3.2.</strong> Hooks &amp; Component State</a></li><li class="chapter-item expanded "><a href="../interactivity/user_input.html"><strong aria-hidden="true">3.3.</strong> User Input</a></li><li class="chapter-item expanded "><a href="../interactivity/sharing_state.html"><strong aria-hidden="true">3.4.</strong> Sharing State</a></li><li class="chapter-item expanded "><a href="../interactivity/custom_hooks.html"><strong aria-hidden="true">3.5.</strong> Custom Hooks</a></li><li class="chapter-item expanded "><a href="../interactivity/dynamic_rendering.html"><strong aria-hidden="true">3.6.</strong> Dynamic Rendering</a></li><li class="chapter-item expanded "><a href="../interactivity/router.html"><strong aria-hidden="true">3.7.</strong> Routing</a></li></ol></li><li class="chapter-item expanded "><a href="../async/index.html"><strong aria-hidden="true">4.</strong> Async</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../async/use_future.html"><strong aria-hidden="true">4.1.</strong> UseFuture</a></li><li class="chapter-item expanded "><a href="../async/use_coroutine.html"><strong aria-hidden="true">4.2.</strong> UseCoroutine</a></li><li class="chapter-item expanded "><a href="../async/spawn.html"><strong aria-hidden="true">4.3.</strong> Spawning Futures</a></li></ol></li><li class="chapter-item expanded "><a href="../best_practices/index.html"><strong aria-hidden="true">5.</strong> Best Practices</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../best_practices/error_handling.html"><strong aria-hidden="true">5.1.</strong> Error Handling</a></li><li class="chapter-item expanded "><a href="../best_practices/antipatterns.html"><strong aria-hidden="true">5.2.</strong> Antipatterns</a></li></ol></li><li class="chapter-item expanded "><a href="../publishing/index.html"><strong aria-hidden="true">6.</strong> Publishing</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../publishing/desktop.html"><strong aria-hidden="true">6.1.</strong> Desktop</a></li><li class="chapter-item expanded "><a href="../publishing/web.html"><strong aria-hidden="true">6.2.</strong> Web</a></li><li class="spacer"></li></ol></li><li class="chapter-item expanded "><a href="../fullstack/index.html"><strong aria-hidden="true">7.</strong> Fullstack</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../fullstack/getting_started.html"><strong aria-hidden="true">7.1.</strong> Getting Started</a></li><li class="chapter-item expanded "><a href="../fullstack/server_functions.html"><strong aria-hidden="true">7.2.</strong> Communicating with the Server</a></li><li class="spacer"></li></ol></li><li class="chapter-item expanded "><a href="../custom_renderer/index.html"><strong aria-hidden="true">8.</strong> Custom Renderer</a></li><li class="spacer"></li><li class="chapter-item expanded "><a href="../contributing/index.html"><strong aria-hidden="true">9.</strong> Contributing</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../contributing/project_structure.html"><strong aria-hidden="true">9.1.</strong> Project Structure</a></li><li class="chapter-item expanded "><a href="../contributing/walkthrough_readme.html" class="active"><strong aria-hidden="true">9.2.</strong> Walkthrough of Internals</a></li><li class="chapter-item expanded "><a href="../contributing/guiding_principles.html"><strong aria-hidden="true">9.3.</strong> Guiding Principles</a></li><li class="chapter-item expanded "><a href="../contributing/roadmap.html"><strong aria-hidden="true">9.4.</strong> Roadmap</a></li></ol></li></ol>
  73. </div>
  74. <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
  75. </nav>
  76. <div id="page-wrapper" class="page-wrapper">
  77. <div class="page">
  78. <div id="menu-bar-hover-placeholder"></div>
  79. <div id="menu-bar" class="menu-bar sticky bordered">
  80. <div class="left-buttons">
  81. <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
  82. <i class="fa fa-bars"></i>
  83. </button>
  84. <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
  85. <i class="fa fa-paint-brush"></i>
  86. </button>
  87. <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
  88. <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
  89. <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
  90. <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
  91. <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
  92. <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
  93. </ul>
  94. <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
  95. <i class="fa fa-search"></i>
  96. </button>
  97. <button id="language-toggle" class="icon-button" type="button" title="Select language" aria-label="Select language" aria-haspopup="true" aria-expanded="false" aria-controls="language-list">
  98. <i class="fa fa-globe"></i>
  99. </button>
  100. <ul id="language-list" class="language-popup" aria-label="Languages" role="menu">
  101. <li role="none"><a href="../../en/contributing/walkthrough_readme.html"><button role="menuitem" class="language" id="light">English</button></a></li>
  102. <li role="none"><a href="../../pt-br/contributing/walkthrough_readme.html"><button role="menuitem" class="language" id="light">Português Brasileiro</button></a></li>
  103. </ul>
  104. </div>
  105. <h1 class="menu-title"></h1>
  106. <div class="right-buttons">
  107. <a href="../print.html" title="Print this book" aria-label="Print this book">
  108. <i id="print-button" class="fa fa-print"></i>
  109. </a>
  110. <a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide" title="Git repository" aria-label="Git repository">
  111. <i id="git-repository-button" class="fa fa-github"></i>
  112. </a>
  113. <a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide/src/contributing/walkthrough_readme.md" title="Suggest an edit" aria-label="Suggest an edit">
  114. <i id="git-edit-button" class="fa fa-edit"></i>
  115. </a>
  116. </div>
  117. </div>
  118. <div id="search-wrapper" class="hidden">
  119. <form id="searchbar-outer" class="searchbar-outer">
  120. <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
  121. </form>
  122. <div id="searchresults-outer" class="searchresults-outer hidden">
  123. <div id="searchresults-header" class="searchresults-header"></div>
  124. <ul id="searchresults">
  125. </ul>
  126. </div>
  127. </div>
  128. <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
  129. <script type="text/javascript">
  130. document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
  131. document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
  132. Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
  133. link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
  134. });
  135. </script>
  136. <div id="content" class="content">
  137. <main>
  138. <h1 id="walkthrough-of-the-hello-world-example-internals"><a class="header" href="#walkthrough-of-the-hello-world-example-internals">Walkthrough of the Hello World Example Internals</a></h1>
  139. <p>This walkthrough will take you through the internals of the Hello World example program. It will explain how major parts of Dioxus internals interact with each other to take the readme example from a source file to a running application. This guide should serve as a high-level overview of the internals of Dioxus. It is not meant to be a comprehensive guide.</p>
  140. <h2 id="the-source-file"><a class="header" href="#the-source-file">The Source File</a></h2>
  141. <p>We start will a hello world program. This program renders a desktop app with the text &quot;Hello World&quot; in a webview.</p>
  142. <pre><pre class="playground"><code class="language-rust edition2018">//! Example: README.md showcase
  143. //!
  144. //! The example from the README.md.
  145. use dioxus::prelude::*;
  146. fn main() {
  147. dioxus_desktop::launch(app);
  148. }
  149. fn app(cx: Scope) -&gt; Element {
  150. let mut count = use_state(cx, || 0);
  151. cx.render(rsx! {
  152. h1 { &quot;High-Five counter: {count}&quot; }
  153. button { onclick: move |_| count += 1, &quot;Up high!&quot; }
  154. button { onclick: move |_| count -= 1, &quot;Down low!&quot; }
  155. })
  156. }
  157. </code></pre></pre>
  158. <p><a href="https://mermaid.live/edit#pako:eNqNkT1vwyAQhv8KvSlR48HphtQtqjK0S6tuSBGBS0CxwcJHk8rxfy_YVqxKVdR3ug_u4YXrQHmNwOFQ-bMyMhB7fReOJbVxfwyyMSy0l7GSpW1ARda727ksUy5MuSyKgvBC5ULA1h5N8WK_kCkfHWHgrBuiXsBynrvdsY9E3u1iM_eyvFOVVadMnELOap-o1911JLPHZ1b-YqLTc3LjTt7WifTZMJPsPdx1ov3Z_ellfcdL8R8vmTy5eUqsTUpZ-vzZzjAEK6gx1NLqtJwuNwSQwRoF8BRqGU4ChOvTORnJf3w7BZxCxBXERkvCjZXpQTXwg6zaVEVtyYe3cdvD0vsf4bucgw"><img src="https://mermaid.ink/img/pako:eNqNkT1vwyAQhv8KvSlR48HphtQtqjK0S6tuSBGBS0CxwcJHk8rxfy_YVqxKVdR3ug_u4YXrQHmNwOFQ-bMyMhB7fReOJbVxfwyyMSy0l7GSpW1ARda727ksUy5MuSyKgvBC5ULA1h5N8WK_kCkfHWHgrBuiXsBynrvdsY9E3u1iM_eyvFOVVadMnELOap-o1911JLPHZ1b-YqLTc3LjTt7WifTZMJPsPdx1ov3Z_ellfcdL8R8vmTy5eUqsTUpZ-vzZzjAEK6gx1NLqtJwuNwSQwRoF8BRqGU4ChOvTORnJf3w7BZxCxBXERkvCjZXpQTXwg6zaVEVtyYe3cdvD0vsf4bucgw?type=png" alt="" /></a></p>
  159. <h2 id="the-rsx-macro"><a class="header" href="#the-rsx-macro">The rsx! Macro</a></h2>
  160. <p>Before the Rust compiler runs the program, it will expand all macros. Here is what the hello world example looks like expanded:</p>
  161. <pre><pre class="playground"><code class="language-rust edition2018">use dioxus::prelude::*;
  162. fn main() {
  163. dioxus_desktop::launch(app);
  164. }
  165. fn app(cx: Scope) -&gt; Element {
  166. let mut count = use_state(cx, || 0);
  167. cx.render(
  168. // rsx expands to LazyNodes::new
  169. ::dioxus::core::LazyNodes::new(
  170. move |__cx: &amp;::dioxus::core::ScopeState| -&gt; ::dioxus::core::VNode {
  171. // The template is every static part of the rsx
  172. static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template {
  173. // This is the source location of the rsx that generated this template. This is used to make hot rsx reloading work. Hot rsx reloading just replaces the template with a new one generated from the rsx by the CLI.
  174. name: &quot;examples\\readme.rs:14:15:250&quot;,
  175. // The root nodes are the top level nodes of the rsx
  176. roots: &amp;[
  177. // The h1 node
  178. ::dioxus::core::TemplateNode::Element {
  179. // Find the built in h1 tag in the dioxus_elements crate exported by the dioxus html crate
  180. tag: dioxus_elements::h1::TAG_NAME,
  181. namespace: dioxus_elements::h1::NAME_SPACE,
  182. attrs: &amp;[],
  183. // The children of the h1 node
  184. children: &amp;[
  185. // The dynamic count text node
  186. // Any nodes that are dynamic have a dynamic placeholder with a unique index
  187. ::dioxus::core::TemplateNode::DynamicText {
  188. // This index is used to find what element in `dynamic_nodes` to use instead of the placeholder
  189. id: 0usize,
  190. },
  191. ],
  192. },
  193. // The up high button node
  194. ::dioxus::core::TemplateNode::Element {
  195. tag: dioxus_elements::button::TAG_NAME,
  196. namespace: dioxus_elements::button::NAME_SPACE,
  197. attrs: &amp;[
  198. // The dynamic onclick listener attribute
  199. // Any attributes that are dynamic have a dynamic placeholder with a unique index.
  200. ::dioxus::core::TemplateAttribute::Dynamic {
  201. // Similar to dynamic nodes, dynamic attributes have a unique index used to find the attribute in `dynamic_attrs` to use instead of the placeholder
  202. id: 0usize,
  203. },
  204. ],
  205. children: &amp;[::dioxus::core::TemplateNode::Text { text: &quot;Up high!&quot; }],
  206. },
  207. // The down low button node
  208. ::dioxus::core::TemplateNode::Element {
  209. tag: dioxus_elements::button::TAG_NAME,
  210. namespace: dioxus_elements::button::NAME_SPACE,
  211. attrs: &amp;[
  212. // The dynamic onclick listener attribute
  213. ::dioxus::core::TemplateAttribute::Dynamic { id: 1usize },
  214. ],
  215. children: &amp;[::dioxus::core::TemplateNode::Text { text: &quot;Down low!&quot; }],
  216. },
  217. ],
  218. // Node paths is a list of paths to every dynamic node in the rsx
  219. node_paths: &amp;[
  220. // The first node path is the path to the dynamic node with an id of 0 (the count text node)
  221. &amp;[
  222. // Go to the index 0 root node
  223. 0u8,
  224. //
  225. // Go to the first child of the root node
  226. 0u8,
  227. ],
  228. ],
  229. // Attr paths is a list of paths to every dynamic attribute in the rsx
  230. attr_paths: &amp;[
  231. // The first attr path is the path to the dynamic attribute with an id of 0 (the up high button onclick listener)
  232. &amp;[
  233. // Go to the index 1 root node
  234. 1u8,
  235. ],
  236. // The second attr path is the path to the dynamic attribute with an id of 1 (the down low button onclick listener)
  237. &amp;[
  238. // Go to the index 2 root node
  239. 2u8,
  240. ],
  241. ],
  242. };
  243. // The VNode is a reference to the template with the dynamic parts of the rsx
  244. ::dioxus::core::VNode {
  245. parent: None,
  246. key: None,
  247. // The static template this node will use. The template is stored in a Cell so it can be replaced with a new template when hot rsx reloading is enabled
  248. template: std::cell::Cell::new(TEMPLATE),
  249. root_ids: Default::default(),
  250. dynamic_nodes: __cx.bump().alloc([
  251. // The dynamic count text node (dynamic node id 0)
  252. __cx.text_node(format_args!(&quot;High-Five counter: {0}&quot;, count)),
  253. ]),
  254. dynamic_attrs: __cx.bump().alloc([
  255. // The dynamic up high button onclick listener (dynamic attribute id 0)
  256. dioxus_elements::events::onclick(__cx, move |_| count += 1),
  257. // The dynamic down low button onclick listener (dynamic attribute id 1)
  258. dioxus_elements::events::onclick(__cx, move |_| count -= 1),
  259. ]),
  260. }
  261. },
  262. ),
  263. )
  264. }
  265. </code></pre></pre>
  266. <p>The rsx macro separates the static parts of the rsx (the template) and the dynamic parts (the dynamic_nodes and dynamic_attributes).</p>
  267. <p>The static template only contains the parts of the rsx that cannot change at runtime with holes for the dynamic parts:</p>
  268. <p><a href="https://mermaid.live/edit#pako:eNqdksFuwjAMhl8l8wkkKtFx65njdtm0E0GVSQKJoEmVOgKEeHecUrXStO0wn5Lf9u8vcm6ggjZQwf4UzspiJPH2Ib3g6NLuELG1oiMkp0TsLs9EDu2iUeSCH8tz2HJmy3lRFPrqsXGq9mxeLzcbCU6LZSUGXWRdwnY7tY7Tdoko-Dq1U64fODgiUfzJMeuOe7_ZGq-ny2jNhGQu9DqT8NUK6w72RcL8dxgdzv4PnHLAKf-Fk80HoBUDrfkqeBkTUd8EC2hMbNBpXtYtJySQNQ0PqPioMR4lSH_nOkwUPq9eQUUxmQWkViOZtUN-UwPVHk8dq0Y7CvH9uf3-E9wfrmuk1A"><img src="https://mermaid.ink/img/pako:eNqdksFuwjAMhl8l8wkkKtFx65njdtm0E0GVSQKJoEmVOgKEeHecUrXStO0wn5Lf9u8vcm6ggjZQwf4UzspiJPH2Ib3g6NLuELG1oiMkp0TsLs9EDu2iUeSCH8tz2HJmy3lRFPrqsXGq9mxeLzcbCU6LZSUGXWRdwnY7tY7Tdoko-Dq1U64fODgiUfzJMeuOe7_ZGq-ny2jNhGQu9DqT8NUK6w72RcL8dxgdzv4PnHLAKf-Fk80HoBUDrfkqeBkTUd8EC2hMbNBpXtYtJySQNQ0PqPioMR4lSH_nOkwUPq9eQUUxmQWkViOZtUN-UwPVHk8dq0Y7CvH9uf3-E9wfrmuk1A?type=png" alt="" /></a></p>
  269. <p>The dynamic_nodes and dynamic_attributes are the parts of the rsx that can change at runtime:</p>
  270. <p><a href="https://mermaid.live/edit#pako:eNp1UcFOwzAM_RXLVzZpvUbighDiABfgtkxTlnirtSaZUgc0df130hZEEcwny35-79nu0EZHqHDfxA9bmyTw9KIDlGjz7pDMqQZ3DsazhVCQ7dQbwnEiKxwDvN3NqhN4O4C3q_VaIztYKXjkQ7184HcCG3MQSgq6Mes1bjbTPAV3RdqIJN5l-V__2_Fcf5iY68dgG7ZHBT4WD5ftZfIBN7dQ_Tj4w1B9MVTXGZa_GMYdcIGekjfsymW7oaFRavKkUZXUmXTUqENfcCZLfD0Hi0pSpgXmkzNC92zKATyqvWnaUiXHEtPz9KrxY_0nzYOPmA"><img src="https://mermaid.ink/img/pako:eNp1UcFOwzAM_RXLVzZpvUbighDiABfgtkxTlnirtSaZUgc0df130hZEEcwny35-79nu0EZHqHDfxA9bmyTw9KIDlGjz7pDMqQZ3DsazhVCQ7dQbwnEiKxwDvN3NqhN4O4C3q_VaIztYKXjkQ7184HcCG3MQSgq6Mes1bjbTPAV3RdqIJN5l-V__2_Fcf5iY68dgG7ZHBT4WD5ftZfIBN7dQ_Tj4w1B9MVTXGZa_GMYdcIGekjfsymW7oaFRavKkUZXUmXTUqENfcCZLfD0Hi0pSpgXmkzNC92zKATyqvWnaUiXHEtPz9KrxY_0nzYOPmA?type=png" alt="" /></a></p>
  271. <h2 id="launching-the-app"><a class="header" href="#launching-the-app">Launching the App</a></h2>
  272. <p>The app is launched by calling the <code>launch</code> function with the root component. Internally, this function will create a new web view using <a href="https://docs.rs/wry/latest/wry/">wry</a> and create a virtual dom with the root component. This guide will not explain the renderer in-depth, but you can read more about it in the <a href="/guide/custom-renderer">custom renderer</a> section.</p>
  273. <h2 id="the-virtual-dom"><a class="header" href="#the-virtual-dom">The Virtual DOM</a></h2>
  274. <p>Before we dive into the initial render in the virtual dom, we need to discuss what the virtual dom is. The virtual dom is a representation of the dom that is used to diff the current dom from the new dom. This diff is then used to create a list of mutations that need to be applied to the dom.</p>
  275. <p>The Virtual Dom roughly looks like this:</p>
  276. <pre><pre class="playground"><code class="language-rust edition2018">
  277. <span class="boring">#![allow(unused)]
  278. </span><span class="boring">fn main() {
  279. </span>pub struct VirtualDom {
  280. // All the templates that have been created or set durring hot reloading
  281. pub(crate) templates: FxHashMap&lt;TemplateId, FxHashMap&lt;usize, Template&lt;'static&gt;&gt;&gt;,
  282. // A slab of all the scopes that have been created
  283. pub(crate) scopes: ScopeSlab,
  284. // All scopes that have been marked as dirty
  285. pub(crate) dirty_scopes: BTreeSet&lt;DirtyScope&gt;,
  286. // Every element is actually a dual reference - one to the template and the other to the dynamic node in that template
  287. pub(crate) elements: Slab&lt;ElementRef&gt;,
  288. // This receiver is used to receive messages from hooks about what scopes need to be marked as dirty
  289. pub(crate) rx: futures_channel::mpsc::UnboundedReceiver&lt;SchedulerMsg&gt;,
  290. // The changes queued up to be sent to the renderer
  291. pub(crate) mutations: Mutations&lt;'static&gt;,
  292. }
  293. <span class="boring">}
  294. </span></code></pre></pre>
  295. <blockquote>
  296. <p>What is a <a href="https://docs.rs/slab/latest/slab/">slab</a>?
  297. A slab acts like a hashmap with integer keys if you don't care about the value of the keys. It is internally backed by a dense vector which makes it more efficient than a hashmap. When you insert a value into a slab, it returns an integer key that you can use to retrieve the value later.</p>
  298. </blockquote>
  299. <blockquote>
  300. <p>How does Dioxus use slabs?
  301. Dioxus uses &quot;synchronized slabs&quot; to communicate between the renderer and the VDOM. When an node is created in the Virtual Dom, a ElementId is passed along with the mutation to the renderer to identify the node. These ids are used by the Virtual Dom to reference that nodes in future mutations like setting an attribute on a node or removing a node.
  302. When the renderer sends an event to the Virtual Dom, it sends the ElementId of the node that the event was triggered on. The Virtual Dom uses this id to find the node in the slab and then run the necessary event handlers.</p>
  303. </blockquote>
  304. <p>The virtual dom is a tree of scopes. A new scope is created for every component when it is first rendered and recycled when the component is unmounted.</p>
  305. <p>Scopes serve three main purposes:</p>
  306. <ol>
  307. <li>They store the state of hooks used by the component</li>
  308. <li>They store the state for the context API</li>
  309. <li>They store the current and previous VNode that was rendered for diffing</li>
  310. </ol>
  311. <h3 id="the-initial-render"><a class="header" href="#the-initial-render">The Initial Render</a></h3>
  312. <p>The root scope is created and rebuilt:</p>
  313. <ol>
  314. <li>The root component is run</li>
  315. <li>The root component returns a VNode</li>
  316. <li>Mutations for the VNode are created and added to the mutation list (this may involve creating new child components)</li>
  317. <li>The VNode is stored in the root scope</li>
  318. </ol>
  319. <p>After the root scope is built, the mutations are sent to the renderer to be applied to the dom.</p>
  320. <p>After the initial render, the root scope looks like this:</p>
  321. <p><a href="https://mermaid.live/edit#pako:eNqtVE1P4zAQ_SuzPrWikRpWXCLtBRDisItWsOxhCaqM7RKricdyJrQV8N93QtvQNCkfEnOynydv3nxkHoVCbUQipjnOVSYDwc_L1AFbWd3dB-kzuEQkuFLoDUwDFkCZAek9nGDh0RlHK__atA1GkUUHf45f0YbppAqB_aOzIAvz-t7-chN_Y-1bw1WSJKsglIu2w9tktWXxIIuHURT5XCqTYa5NmDguw2R8c5MKq2GcgF46WTB_jafi9rZL0yi5q4jQTSrf9altO4okCn1Ratwyz55Qxuku2ITlTMgs6HCQimsPmb3PvqVi-L5gjXP3QcnxWnL8JZLrwGvR31n0KV-Bx6-r-oVkT_-3G1S-NQLbk9i8rj7udP2cixed2QcDCitHJiQw7ub3EVlNecrPjudG2-6soFO5VbMECmR9T5OnlUY4-AFxfw9aTFst3McU9TK1Otm6NEn_DubBYlX2_dglLXOz48FgwJmJ5lZTlhz6xWgNaFnyDgpymcARHO0W2a9J_l5w2wYXvHuGPcqaQ-rESBQmFNJq3nCPNZoK3l4sUSR81DLMUpG6Z_aTFeHV0imRUKjMSFReSzKnVnKGhUimMi8ZNdoShl-rlfmyOUfCS_cPcePz_B_Wl4pc"><img src="https://mermaid.ink/img/pako:eNqtVE1P4zAQ_SuzPrWikRpWXCLtBRDisItWsOxhCaqM7RKricdyJrQV8N93QtvQNCkfEnOynydv3nxkHoVCbUQipjnOVSYDwc_L1AFbWd3dB-kzuEQkuFLoDUwDFkCZAek9nGDh0RlHK__atA1GkUUHf45f0YbppAqB_aOzIAvz-t7-chN_Y-1bw1WSJKsglIu2w9tktWXxIIuHURT5XCqTYa5NmDguw2R8c5MKq2GcgF46WTB_jafi9rZL0yi5q4jQTSrf9altO4okCn1Ratwyz55Qxuku2ITlTMgs6HCQimsPmb3PvqVi-L5gjXP3QcnxWnL8JZLrwGvR31n0KV-Bx6-r-oVkT_-3G1S-NQLbk9i8rj7udP2cixed2QcDCitHJiQw7ub3EVlNecrPjudG2-6soFO5VbMECmR9T5OnlUY4-AFxfw9aTFst3McU9TK1Otm6NEn_DubBYlX2_dglLXOz48FgwJmJ5lZTlhz6xWgNaFnyDgpymcARHO0W2a9J_l5w2wYXvHuGPcqaQ-rESBQmFNJq3nCPNZoK3l4sUSR81DLMUpG6Z_aTFeHV0imRUKjMSFReSzKnVnKGhUimMi8ZNdoShl-rlfmyOUfCS_cPcePz_B_Wl4pc?type=png" alt="" /></a></p>
  322. <h3 id="waiting-for-events"><a class="header" href="#waiting-for-events">Waiting for Events</a></h3>
  323. <p>The Virtual Dom will only ever rerender a scope if it is marked as dirty. Each hook is responsible for marking the scope as dirty if the state has changed. Hooks can mark a scope as dirty by sending a message to the Virtual Dom's channel.</p>
  324. <p>There are generally two ways a scope is marked as dirty:</p>
  325. <ol>
  326. <li>The renderer triggers an event: This causes an event listener to be called if needed which may mark a component as dirty</li>
  327. <li>The renderer calls wait for work: This polls futures which may mark a component as dirty</li>
  328. </ol>
  329. <p>Once at least one scope is marked as dirty, the renderer can call <code>render_with_deadline</code> to diff the dirty scopes.</p>
  330. <h3 id="diffing-scopes"><a class="header" href="#diffing-scopes">Diffing Scopes</a></h3>
  331. <p>If the user clicked the &quot;up high&quot; button, the root scope would be marked as dirty by the use_state hook. Once the desktop renderer calls <code>render_with_deadline</code>, the root scope would be diffed.</p>
  332. <p>To start the diffing process, the component is run. After the root component is run it will look like this:</p>
  333. <p><a href="https://mermaid.live/edit#pako:eNrFVlFP2zAQ_iuen0BrpCaIl0i8AEJ72KQJtpcRFBnbJVYTn-U4tBXw33dpG5M2CetoBfdkny_ffb67fPIT5SAkjekkhxnPmHXk-3WiCVpZ3T9YZjJyDeDIDQcjycRCQVwmCTOGXEBhQEvtVvG1CWUldwo0-XX-6vVIF5W1GB9cWVbI1_PNL5v8jW3uPFbpmFOc2HK-GfA2WG1ZeJSFx0EQmJxxmUEupE01liEd394mVAkyjolYaFYgfu1P6N1dF8Yzua-cA51WphtTWzsLc872Zan9CnEGUkktuk6fFm_i5NxFRwn9bUimHrIvCT3-N2EBM70j5XBNOTwI5TrxmvQJkr7ELcHx67Jeggz0v92g8q0RaE-iP1193On6NyxecKUeJeFQaSdtTMLu_Xah5ctT_u94Nty2ZwU0zxWfxqQA5PecPq84kq9nfRw7SK0WDiEFZ4O37d34S_-08lFBVfb92KVb5HIrAp0WpjKYKeGyODLz0dohWIkaZNkiJqfkdLvIH6oRaTSoEmm0n06k0a5K0ZdpL61Io0Yt0nfpxc7UQ0_9cJrhyZ8syX-6brS706Mc489Vjja7fbWj3cxDqIdfJJqOaCFtwZTAV8hT7U0ovjBQRmiMS8HsNKGJfsE4Vjm4WWhOY2crOaKVEczJS8WwgAWNJywv0SuFcmB_rJ41y9fNiBqm_wA0MS9_AUuAiy0"><img src="https://mermaid.ink/img/pako:eNrFVlFP2zAQ_iuen0BrpCaIl0i8AEJ72KQJtpcRFBnbJVYTn-U4tBXw33dpG5M2CetoBfdkny_ffb67fPIT5SAkjekkhxnPmHXk-3WiCVpZ3T9YZjJyDeDIDQcjycRCQVwmCTOGXEBhQEvtVvG1CWUldwo0-XX-6vVIF5W1GB9cWVbI1_PNL5v8jW3uPFbpmFOc2HK-GfA2WG1ZeJSFx0EQmJxxmUEupE01liEd394mVAkyjolYaFYgfu1P6N1dF8Yzua-cA51WphtTWzsLc872Zan9CnEGUkktuk6fFm_i5NxFRwn9bUimHrIvCT3-N2EBM70j5XBNOTwI5TrxmvQJkr7ELcHx67Jeggz0v92g8q0RaE-iP1193On6NyxecKUeJeFQaSdtTMLu_Xah5ctT_u94Nty2ZwU0zxWfxqQA5PecPq84kq9nfRw7SK0WDiEFZ4O37d34S_-08lFBVfb92KVb5HIrAp0WpjKYKeGyODLz0dohWIkaZNkiJqfkdLvIH6oRaTSoEmm0n06k0a5K0ZdpL61Io0Yt0nfpxc7UQ0_9cJrhyZ8syX-6brS706Mc489Vjja7fbWj3cxDqIdfJJqOaCFtwZTAV8hT7U0ovjBQRmiMS8HsNKGJfsE4Vjm4WWhOY2crOaKVEczJS8WwgAWNJywv0SuFcmB_rJ41y9fNiBqm_wA0MS9_AUuAiy0?type=png" alt="" /></a></p>
  334. <p>Next, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.</p>
  335. <p>When a component is re-rendered, the Virtual Dom will compare the new VNode with the previous VNode and only update the parts of the tree that have changed.</p>
  336. <p>The diffing algorithm goes through the list of dynamic attributes and nodes and compares them to the previous VNode. If the attribute or node has changed, a mutation that describes the change is added to the mutation list.</p>
  337. <p>Here is what the diffing algorithm looks like for the root scope (red lines indicate that a mutation was generated, and green lines indicate that no mutation was generated)</p>
  338. <p><a href="https://mermaid.live/edit#pako:eNrFlFFPwjAQx7_KpT7Kko2Elya8qCE-aGLAJ5khpe1Yw9Zbug4k4He3OJjbGPig0T5t17tf_nf777aEo5CEkijBNY-ZsfAwDjW4kxfzhWFZDGNECxOOmYTIYAo2lsCyDG4xzVBLbcv8_RHKSG4V6orSIN0Wxrh8b2RYKr_uTyubd1W92GiWKg7aac6bOU3G803HbVk82xfP_Ok0JEqAT-FeLWJvpFYSOBbaSkMhCMnra5MgtfhWFrPWqHlhL2urT6atbU-oa0PNE8WXFFJ0-nazXakRroddGk9IwYEUnCd5w7Pddr5UTT8ZuVJY5F0fM7ebRLYyXNDgUnprJWxM-9lb7xAQLHe-M2xDYQCD9pD_2hez_kVn-P_rjLq6n3qjYv2iO5qz9DyvPdyv1ETp5eTTJ_7BGvQq8v1TVtl5jXUcRRcrqFh-dI4VtFlBN6t_ynLNkh5JpUmZEm5rbvfhkLiN6H4BQt2jYGYZklC_uzxWWJxsNCfUmkL2SJEJZuWdYs4cKaERS3IXlUJZNI_lGv7cxj2SMf2CeMx5_wBcbK19"><img src="https://mermaid.ink/img/pako:eNrFlFFPwjAQx7_KpT7Kko2Elya8qCE-aGLAJ5khpe1Yw9Zbug4k4He3OJjbGPig0T5t17tf_nf777aEo5CEkijBNY-ZsfAwDjW4kxfzhWFZDGNECxOOmYTIYAo2lsCyDG4xzVBLbcv8_RHKSG4V6orSIN0Wxrh8b2RYKr_uTyubd1W92GiWKg7aac6bOU3G803HbVk82xfP_Ok0JEqAT-FeLWJvpFYSOBbaSkMhCMnra5MgtfhWFrPWqHlhL2urT6atbU-oa0PNE8WXFFJ0-nazXakRroddGk9IwYEUnCd5w7Pddr5UTT8ZuVJY5F0fM7ebRLYyXNDgUnprJWxM-9lb7xAQLHe-M2xDYQCD9pD_2hez_kVn-P_rjLq6n3qjYv2iO5qz9DyvPdyv1ETp5eTTJ_7BGvQq8v1TVtl5jXUcRRcrqFh-dI4VtFlBN6t_ynLNkh5JpUmZEm5rbvfhkLiN6H4BQt2jYGYZklC_uzxWWJxsNCfUmkL2SJEJZuWdYs4cKaERS3IXlUJZNI_lGv7cxj2SMf2CeMx5_wBcbK19?type=png" alt="" /></a></p>
  339. <h2 id="conclusion"><a class="header" href="#conclusion">Conclusion</a></h2>
  340. <p>This is only a brief overview of how the Virtual Dom works. There are several aspects not yet covered in this guide including how the Virtual Dom handles async-components, keyed diffing, and how it uses <a href="https://github.com/fitzgen/bumpalo">bump allocation</a> to efficiently allocate VNodes. If need more information about the Virtual Dom, you can read the code of the <a href="https://github.com/DioxusLabs/dioxus/tree/master/packages/core">core</a> crate or reach out to us on <a href="https://discord.gg/XgGxMSkvUM">Discord</a>.</p>
  341. </main>
  342. <nav class="nav-wrapper" aria-label="Page navigation">
  343. <!-- Mobile navigation buttons -->
  344. <a rel="prev" href="../contributing/project_structure.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
  345. <i class="fa fa-angle-left"></i>
  346. </a>
  347. <a rel="next" href="../contributing/guiding_principles.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
  348. <i class="fa fa-angle-right"></i>
  349. </a>
  350. <div style="clear: both"></div>
  351. </nav>
  352. </div>
  353. </div>
  354. <nav class="nav-wide-wrapper" aria-label="Page navigation">
  355. <a rel="prev" href="../contributing/project_structure.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
  356. <i class="fa fa-angle-left"></i>
  357. </a>
  358. <a rel="next" href="../contributing/guiding_principles.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
  359. <i class="fa fa-angle-right"></i>
  360. </a>
  361. </nav>
  362. </div>
  363. <script type="text/javascript">
  364. window.playground_line_numbers = true;
  365. </script>
  366. <script type="text/javascript">
  367. window.playground_copyable = true;
  368. </script>
  369. <script src="../ace.js" type="text/javascript" charset="utf-8"></script>
  370. <script src="../editor.js" type="text/javascript" charset="utf-8"></script>
  371. <script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
  372. <script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
  373. <script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
  374. <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
  375. <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
  376. <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
  377. <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
  378. <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
  379. <script src="../book.js" type="text/javascript" charset="utf-8"></script>
  380. <!-- Custom JS scripts -->
  381. </body>
  382. </html>