custom_hooks.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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>Custom Hooks</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" class="active"><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"><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/interactivity/custom_hooks.html"><button role="menuitem" class="language" id="light">English</button></a></li>
  102. <li role="none"><a href="../../pt-br/interactivity/custom_hooks.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/interactivity/custom_hooks.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="custom-hooks"><a class="header" href="#custom-hooks">Custom Hooks</a></h1>
  139. <p>Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own.</p>
  140. <p>When writing your hook, you can make a function that accepts <code>cx: &amp;ScopeState</code> as a parameter to accept a scope with any Props.</p>
  141. <h2 id="composing-hooks"><a class="header" href="#composing-hooks">Composing Hooks</a></h2>
  142. <p>To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook.</p>
  143. <p>For example, if many components need to access an <code>AppSettings</code> struct, you can create a &quot;shortcut&quot; hook:</p>
  144. <pre><pre class="playground"><code class="language-rust edition2018">
  145. <span class="boring">#![allow(unused)]
  146. </span><span class="boring">fn main() {
  147. </span>fn use_settings(cx: &amp;ScopeState) -&gt; &amp;UseSharedState&lt;AppSettings&gt; {
  148. use_shared_state::&lt;AppSettings&gt;(cx).expect(&quot;App settings not provided&quot;)
  149. }
  150. <span class="boring">}
  151. </span></code></pre></pre>
  152. <p>Or if you want to wrap a hook that persists reloads with the storage API, you can build on top of the use_ref hook to work with mutable state:</p>
  153. <pre><pre class="playground"><code class="language-rust edition2018">
  154. <span class="boring">#![allow(unused)]
  155. </span><span class="boring">fn main() {
  156. </span>use gloo_storage::{LocalStorage, Storage};
  157. use serde::{de::DeserializeOwned, Serialize};
  158. /// A persistent storage hook that can be used to store data across application reloads.
  159. #[allow(clippy::needless_return)]
  160. pub fn use_persistent&lt;T: Serialize + DeserializeOwned + Default + 'static&gt;(
  161. cx: &amp;ScopeState,
  162. // A unique key for the storage entry
  163. key: impl ToString,
  164. // A function that returns the initial value if the storage entry is empty
  165. init: impl FnOnce() -&gt; T,
  166. ) -&gt; &amp;UsePersistent&lt;T&gt; {
  167. // Use the use_ref hook to create a mutable state for the storage entry
  168. let state = use_ref(cx, move || {
  169. // This closure will run when the hook is created
  170. let key = key.to_string();
  171. let value = LocalStorage::get(key.as_str()).ok().unwrap_or_else(init);
  172. StorageEntry { key, value }
  173. });
  174. // Wrap the state in a new struct with a custom API
  175. // Note: We use use_hook here so that this hook is easier to use in closures in the rsx. Any values with the same lifetime as the ScopeState can be used in the closure without cloning.
  176. cx.use_hook(|| UsePersistent {
  177. inner: state.clone(),
  178. })
  179. }
  180. struct StorageEntry&lt;T&gt; {
  181. key: String,
  182. value: T,
  183. }
  184. /// Storage that persists across application reloads
  185. pub struct UsePersistent&lt;T: 'static&gt; {
  186. inner: UseRef&lt;StorageEntry&lt;T&gt;&gt;,
  187. }
  188. impl&lt;T: Serialize + DeserializeOwned + Clone + 'static&gt; UsePersistent&lt;T&gt; {
  189. /// Returns a reference to the value
  190. pub fn get(&amp;self) -&gt; T {
  191. self.inner.read().value.clone()
  192. }
  193. /// Sets the value
  194. pub fn set(&amp;self, value: T) {
  195. let mut inner = self.inner.write();
  196. // Write the new value to local storage
  197. LocalStorage::set(inner.key.as_str(), &amp;value);
  198. inner.value = value;
  199. }
  200. }
  201. <span class="boring">}
  202. </span></code></pre></pre>
  203. <h2 id="custom-hook-logic"><a class="header" href="#custom-hook-logic">Custom Hook Logic</a></h2>
  204. <p>You can use <a href="https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.use_hook"><code>cx.use_hook</code></a> to build your own hooks. In fact, this is what all the standard hooks are built on!</p>
  205. <p><code>use_hook</code> accepts a single closure for initializing the hook. It will be only run the first time the component is rendered. The return value of that closure will be used as the value of the hook – Dioxus will take it, and store it for as long as the component is alive. On every render (not just the first one!), you will get a reference to this value.</p>
  206. <blockquote>
  207. <p>Note: You can implement <a href="https://doc.rust-lang.org/std/ops/trait.Drop.html"><code>Drop</code></a> for your hook value – it will be dropped then the component is unmounted (no longer in the UI)</p>
  208. </blockquote>
  209. <p>Inside the initialization closure, you will typically make calls to other <code>cx</code> methods. For example:</p>
  210. <ul>
  211. <li>The <code>use_state</code> hook tracks state in the hook value, and uses <a href="https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.schedule_update"><code>cx.schedule_update</code></a> to make Dioxus re-render the component whenever it changes.</li>
  212. </ul>
  213. <p>Here is a simplified implementation of the <code>use_state</code> hook:</p>
  214. <pre><pre class="playground"><code class="language-rust edition2018">
  215. <span class="boring">#![allow(unused)]
  216. </span><span class="boring">fn main() {
  217. </span>use std::cell::RefCell;
  218. use std::rc::Rc;
  219. use std::sync::Arc;
  220. #[derive(Clone)]
  221. struct UseState&lt;T&gt; {
  222. value: Rc&lt;RefCell&lt;T&gt;&gt;,
  223. update: Arc&lt;dyn Fn()&gt;,
  224. }
  225. fn my_use_state&lt;T: 'static&gt;(cx: &amp;ScopeState, init: impl FnOnce() -&gt; T) -&gt; &amp;UseState&lt;T&gt; {
  226. cx.use_hook(|| {
  227. // The update function will trigger a re-render in the component cx is attached to
  228. let update = cx.schedule_update();
  229. // Create the initial state
  230. let value = Rc::new(RefCell::new(init()));
  231. UseState { value, update }
  232. })
  233. }
  234. impl&lt;T: Clone&gt; UseState&lt;T&gt; {
  235. fn get(&amp;self) -&gt; T {
  236. self.value.borrow().clone()
  237. }
  238. fn set(&amp;self, value: T) {
  239. // Update the state
  240. *self.value.borrow_mut() = value;
  241. // Trigger a re-render on the component the state is from
  242. (self.update)();
  243. }
  244. }
  245. <span class="boring">}
  246. </span></code></pre></pre>
  247. <ul>
  248. <li>The <code>use_context</code> hook calls <a href="https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.consume_context"><code>cx.consume_context</code></a> (which would be expensive to call on every render) to get some context from the scope</li>
  249. </ul>
  250. <p>Here is an implementation of the <code>use_context</code> and <code>use_context_provider</code> hooks:</p>
  251. <pre><pre class="playground"><code class="language-rust edition2018">
  252. <span class="boring">#![allow(unused)]
  253. </span><span class="boring">fn main() {
  254. </span>pub fn use_context&lt;T: 'static + Clone&gt;(cx: &amp;ScopeState) -&gt; Option&lt;&amp;T&gt; {
  255. cx.use_hook(|| cx.consume_context::&lt;T&gt;()).as_ref()
  256. }
  257. pub fn use_context_provider&lt;T: 'static + Clone&gt;(cx: &amp;ScopeState, f: impl FnOnce() -&gt; T) -&gt; &amp;T {
  258. cx.use_hook(|| {
  259. let val = f();
  260. // Provide the context state to the scope
  261. cx.provide_context(val.clone());
  262. val
  263. })
  264. }
  265. <span class="boring">}
  266. </span></code></pre></pre>
  267. <h2 id="hook-anti-patterns"><a class="header" href="#hook-anti-patterns">Hook Anti-Patterns</a></h2>
  268. <p>When writing a custom hook, you should avoid the following anti-patterns:</p>
  269. <ul>
  270. <li>!Clone Hooks: To allow hooks to be used within async blocks, the hooks must be Clone. To make a hook clone, you can wrap data in Rc or Arc and avoid lifetimes in hooks.</li>
  271. </ul>
  272. <p>This version of use_state may seem more efficient, but it is not cloneable:</p>
  273. <pre><pre class="playground"><code class="language-rust edition2018">
  274. <span class="boring">#![allow(unused)]
  275. </span><span class="boring">fn main() {
  276. </span>use std::cell::RefCell;
  277. use std::rc::Rc;
  278. use std::sync::Arc;
  279. struct UseState&lt;'a, T&gt; {
  280. value: &amp;'a RefCell&lt;T&gt;,
  281. update: Arc&lt;dyn Fn()&gt;,
  282. }
  283. fn my_use_state&lt;T: 'static&gt;(cx: &amp;ScopeState, init: impl FnOnce() -&gt; T) -&gt; UseState&lt;T&gt; {
  284. // The update function will trigger a re-render in the component cx is attached to
  285. let update = cx.schedule_update();
  286. // Create the initial state
  287. let value = cx.use_hook(|| RefCell::new(init()));
  288. UseState { value, update }
  289. }
  290. impl&lt;T: Clone&gt; UseState&lt;'_, T&gt; {
  291. fn get(&amp;self) -&gt; T {
  292. self.value.borrow().clone()
  293. }
  294. fn set(&amp;self, value: T) {
  295. // Update the state
  296. *self.value.borrow_mut() = value;
  297. // Trigger a re-render on the component the state is from
  298. (self.update)();
  299. }
  300. }
  301. <span class="boring">}
  302. </span></code></pre></pre>
  303. <p>If we try to use this hook in an async block, we will get a compile error:</p>
  304. <pre><pre class="playground"><code class="language-rust edition2018">
  305. <span class="boring">#![allow(unused)]
  306. </span><span class="boring">fn main() {
  307. </span>fn FutureComponent(cx: &amp;ScopeState) -&gt; Element {
  308. let my_state = my_use_state(cx, || 0);
  309. cx.spawn({
  310. to_owned![my_state];
  311. async move {
  312. my_state.set(1);
  313. }
  314. });
  315. todo!()
  316. }
  317. <span class="boring">}
  318. </span></code></pre></pre>
  319. <p>But with the original version, we can use it in an async block:</p>
  320. <pre><pre class="playground"><code class="language-rust edition2018">
  321. <span class="boring">#![allow(unused)]
  322. </span><span class="boring">fn main() {
  323. </span>fn FutureComponent(cx: &amp;ScopeState) -&gt; Element {
  324. let my_state = use_state(cx, || 0);
  325. cx.spawn({
  326. to_owned![my_state];
  327. async move {
  328. my_state.set(1);
  329. }
  330. });
  331. todo!()
  332. }
  333. <span class="boring">}
  334. </span></code></pre></pre>
  335. </main>
  336. <nav class="nav-wrapper" aria-label="Page navigation">
  337. <!-- Mobile navigation buttons -->
  338. <a rel="prev" href="../interactivity/sharing_state.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
  339. <i class="fa fa-angle-left"></i>
  340. </a>
  341. <a rel="next" href="../interactivity/dynamic_rendering.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
  342. <i class="fa fa-angle-right"></i>
  343. </a>
  344. <div style="clear: both"></div>
  345. </nav>
  346. </div>
  347. </div>
  348. <nav class="nav-wide-wrapper" aria-label="Page navigation">
  349. <a rel="prev" href="../interactivity/sharing_state.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
  350. <i class="fa fa-angle-left"></i>
  351. </a>
  352. <a rel="next" href="../interactivity/dynamic_rendering.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
  353. <i class="fa fa-angle-right"></i>
  354. </a>
  355. </nav>
  356. </div>
  357. <script type="text/javascript">
  358. window.playground_line_numbers = true;
  359. </script>
  360. <script type="text/javascript">
  361. window.playground_copyable = true;
  362. </script>
  363. <script src="../ace.js" type="text/javascript" charset="utf-8"></script>
  364. <script src="../editor.js" type="text/javascript" charset="utf-8"></script>
  365. <script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
  366. <script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
  367. <script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
  368. <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
  369. <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
  370. <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
  371. <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
  372. <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
  373. <script src="../book.js" type="text/javascript" charset="utf-8"></script>
  374. <!-- Custom JS scripts -->
  375. </body>
  376. </html>