123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <!DOCTYPE HTML>
- <html lang="en" class="sidebar-visible no-js light">
- <head>
- <!-- Book generated using mdBook -->
- <meta charset="UTF-8">
- <title>Hooks & Component State</title>
- <!-- Custom HTML head -->
-
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
- <meta name="description" content="">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <meta name="theme-color" content="#ffffff" />
- <link rel="icon" href="../favicon.svg">
- <link rel="shortcut icon" href="../favicon.png">
- <link rel="stylesheet" href="../css/variables.css">
- <link rel="stylesheet" href="../css/general.css">
- <link rel="stylesheet" href="../css/chrome.css">
- <link rel="stylesheet" href="../css/print.css" media="print">
- <!-- Fonts -->
- <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
- <link rel="stylesheet" href="../fonts/fonts.css">
- <!-- Highlight.js Stylesheets -->
- <link rel="stylesheet" href="../highlight.css">
- <link rel="stylesheet" href="../tomorrow-night.css">
- <link rel="stylesheet" href="../ayu-highlight.css">
- <!-- Custom theme stylesheets -->
- <!-- MathJax -->
- <script async type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
- </head>
- <body>
- <!-- Provide site root to javascript -->
- <script type="text/javascript">
- var path_to_root = "../";
- var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
- </script>
- <!-- Work around some values being stored in localStorage wrapped in quotes -->
- <script type="text/javascript">
- try {
- var theme = localStorage.getItem('mdbook-theme');
- var sidebar = localStorage.getItem('mdbook-sidebar');
- if (theme.startsWith('"') && theme.endsWith('"')) {
- localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
- }
- if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
- localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
- }
- } catch (e) { }
- </script>
- <!-- Set the theme before any content is loaded, prevents flash -->
- <script type="text/javascript">
- var theme;
- try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
- if (theme === null || theme === undefined) { theme = default_theme; }
- var html = document.querySelector('html');
- html.classList.remove('no-js')
- html.classList.remove('light')
- html.classList.add(theme);
- html.classList.add('js');
- </script>
- <!-- Hide / unhide sidebar before it is displayed -->
- <script type="text/javascript">
- var html = document.querySelector('html');
- var sidebar = 'hidden';
- if (document.body.clientWidth >= 1080) {
- try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
- sidebar = sidebar || 'visible';
- }
- html.classList.remove('sidebar-visible');
- html.classList.add("sidebar-" + sidebar);
- </script>
- <nav id="sidebar" class="sidebar" aria-label="Table of contents">
- <div class="sidebar-scrollbox">
- <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" class="active"><strong aria-hidden="true">3.2.</strong> Hooks & 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"><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>
- </div>
- <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
- </nav>
- <div id="page-wrapper" class="page-wrapper">
- <div class="page">
- <div id="menu-bar-hover-placeholder"></div>
- <div id="menu-bar" class="menu-bar sticky bordered">
- <div class="left-buttons">
- <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
- <i class="fa fa-bars"></i>
- </button>
- <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">
- <i class="fa fa-paint-brush"></i>
- </button>
- <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
- <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
- <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
- <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
- <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
- <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
- </ul>
- <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">
- <i class="fa fa-search"></i>
- </button>
- <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">
- <i class="fa fa-globe"></i>
- </button>
- <ul id="language-list" class="language-popup" aria-label="Languages" role="menu">
- <li role="none"><a href="../../en/interactivity/hooks.html"><button role="menuitem" class="language" id="light">English</button></a></li>
- <li role="none"><a href="../../pt-br/interactivity/hooks.html"><button role="menuitem" class="language" id="light">Português Brasileiro</button></a></li>
- </ul>
- </div>
- <h1 class="menu-title"></h1>
- <div class="right-buttons">
- <a href="../print.html" title="Print this book" aria-label="Print this book">
- <i id="print-button" class="fa fa-print"></i>
- </a>
- <a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide" title="Git repository" aria-label="Git repository">
- <i id="git-repository-button" class="fa fa-github"></i>
- </a>
- <a href="https://github.com/DioxusLabs/dioxus/edit/master/docs/guide/src/interactivity/hooks.md" title="Suggest an edit" aria-label="Suggest an edit">
- <i id="git-edit-button" class="fa fa-edit"></i>
- </a>
- </div>
- </div>
- <div id="search-wrapper" class="hidden">
- <form id="searchbar-outer" class="searchbar-outer">
- <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
- </form>
- <div id="searchresults-outer" class="searchresults-outer hidden">
- <div id="searchresults-header" class="searchresults-header"></div>
- <ul id="searchresults">
- </ul>
- </div>
- </div>
- <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
- <script type="text/javascript">
- document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
- document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
- Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
- link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
- });
- </script>
- <div id="content" class="content">
- <main>
- <h1 id="hooks-and-component-state"><a class="header" href="#hooks-and-component-state">Hooks and Component State</a></h1>
- <p>So far our components have had no state like a normal rust functions. However, in a UI component, it is often useful to have stateful functionality to build user interactions. For example, you might want to track whether the user has opened a drop-down, and render different things accordingly.</p>
- <p>Hooks allow us to create state in our components. Hooks are Rust functions that take a reference to <code>ScopeState</code> (in a component, you can pass <code>cx</code>), and provide you with functionality and state.</p>
- <h2 id="use_state-hook"><a class="header" href="#use_state-hook"><code>use_state</code> Hook</a></h2>
- <p><a href="https://docs.rs/dioxus/latest/dioxus/prelude/fn.use_state.html"><code>use_state</code></a> is one of the simplest hooks.</p>
- <ul>
- <li>You provide a closure that determines the initial value</li>
- <li><code>use_state</code> gives you the current value, and a way to update it by setting it to something else</li>
- <li>When the value updates, <code>use_state</code> makes the component re-render, and provides you with the new value</li>
- </ul>
- <p>For example, you might have seen the counter example, in which state (a number) is tracked using the <code>use_state</code> hook:</p>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>fn App(cx: Scope) -> Element {
- // count will be initialized to 0 the first time the component is rendered
- let mut count = use_state(cx, || 0);
- cx.render(rsx!(
- h1 { "High-Five counter: {count}" }
- button {
- onclick: move |_| {
- // changing the count will cause the component to re-render
- count += 1
- },
- "Up high!"
- }
- button {
- onclick: move |_| {
- // changing the count will cause the component to re-render
- count -= 1
- },
- "Down low!"
- }
- ))
- }
- <span class="boring">}
- </span></code></pre></pre>
- <p><img src="./images/counter.png" alt="Screenshot: counter app" /></p>
- <p>Every time the component's state changes, it re-renders, and the component function is called, so you can describe what you want the new UI to look like. You don't have to worry about "changing" anything – just describe what you want in terms of the state, and Dioxus will take care of the rest!</p>
- <blockquote>
- <p><code>use_state</code> returns your value wrapped in a smart pointer of type <a href="https://docs.rs/dioxus/latest/dioxus/prelude/struct.UseState.html"><code>UseState</code></a>. This is why you can both read the value and update it, even within an event handler.</p>
- </blockquote>
- <p>You can use multiple hooks in the same component if you want:</p>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>fn App(cx: Scope) -> Element {
- let mut count_a = use_state(cx, || 0);
- let mut count_b = use_state(cx, || 0);
- cx.render(rsx!(
- h1 { "Counter_a: {count_a}" }
- button { onclick: move |_| count_a += 1, "a++" }
- button { onclick: move |_| count_a -= 1, "a--" }
- h1 { "Counter_b: {count_b}" }
- button { onclick: move |_| count_b += 1, "b++" }
- button { onclick: move |_| count_b -= 1, "b--" }
- ))
- }
- <span class="boring">}
- </span></code></pre></pre>
- <p><img src="./images/counter_two_state.png" alt="Screenshot: app with two counters" /></p>
- <h2 id="rules-of-hooks"><a class="header" href="#rules-of-hooks">Rules of Hooks</a></h2>
- <p>The above example might seem a bit magic, since Rust functions are typically not associated with state. Dioxus allows hooks to maintain state across renders through a reference to <code>ScopeState</code>, which is why you must pass <code>&cx</code> to them.</p>
- <p>But how can Dioxus differentiate between multiple hooks in the same component? As you saw in the second example, both <code>use_state</code> functions were called with the same parameters, so how come they can return different things when the counters are different?</p>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span> let mut count_a = use_state(cx, || 0);
- let mut count_b = use_state(cx, || 0);
- <span class="boring">}
- </span></code></pre></pre>
- <p>This is only possible because the two hooks are always called in the same order, so Dioxus knows which is which. Because the order you call hooks matters, you must follow certain rules when using hooks:</p>
- <ol>
- <li>Hooks may be only used in components or other hooks (we'll get to that later)</li>
- <li>On every call to the component function
- <ol>
- <li>The same hooks must be called (except in the case of early returns, as explained later in the <a href="../best_practices/error_handling.html">Error Handling chapter</a>)</li>
- <li>In the same order</li>
- </ol>
- </li>
- <li>Hooks name's should start with <code>use_</code> so you don't accidentally confuse them with regular functions</li>
- </ol>
- <p>These rules mean that there are certain things you can't do with hooks:</p>
- <h3 id="no-hooks-in-conditionals"><a class="header" href="#no-hooks-in-conditionals">No Hooks in Conditionals</a></h3>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>// ❌ don't call hooks in conditionals!
- // We must ensure that the same hooks will be called every time
- // But `if` statements only run if the conditional is true!
- // So we might violate rule 2.
- if you_are_happy && you_know_it {
- let something = use_state(cx, || "hands");
- println!("clap your {something}")
- }
- // ✅ instead, *always* call use_state
- // You can put other stuff in the conditional though
- let something = use_state(cx, || "hands");
- if you_are_happy && you_know_it {
- println!("clap your {something}")
- }
- <span class="boring">}
- </span></code></pre></pre>
- <h3 id="no-hooks-in-closures"><a class="header" href="#no-hooks-in-closures">No Hooks in Closures</a></h3>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>// ❌ don't call hooks inside closures!
- // We can't guarantee that the closure, if used, will be called in the same order every time
- let _a = || {
- let b = use_state(cx, || 0);
- b.get()
- };
- // ✅ instead, move hook `b` outside
- let b = use_state(cx, || 0);
- let _a = || b.get();
- <span class="boring">}
- </span></code></pre></pre>
- <h3 id="no-hooks-in-loops"><a class="header" href="#no-hooks-in-loops">No Hooks in Loops</a></h3>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>// `names` is a Vec<&str>
- // ❌ Do not use hooks in loops!
- // In this case, if the length of the Vec changes, we break rule 2
- for _name in &names {
- let is_selected = use_state(cx, || false);
- println!("selected: {is_selected}");
- }
- // ✅ Instead, use a hashmap with use_ref
- let selection_map = use_ref(cx, HashMap::<&str, bool>::new);
- for name in &names {
- let is_selected = selection_map.read()[name];
- println!("selected: {is_selected}");
- }
- <span class="boring">}
- </span></code></pre></pre>
- <h2 id="use_ref-hook"><a class="header" href="#use_ref-hook"><code>use_ref</code> Hook</a></h2>
- <p><code>use_state</code> is great for tracking simple values. However, you may notice in the <a href="https://docs.rs/dioxus/latest/dioxus/hooks/struct.UseState.html"><code>UseState</code> API</a> that the only way to modify its value is to replace it with something else (e.g., by calling <code>set</code>, or through one of the <code>+=</code>, <code>-=</code> operators). This works well when it is cheap to construct a value (such as any primitive). But what if you want to maintain more complex data in the components state?</p>
- <p>For example, suppose we want to maintain a <code>Vec</code> of values. If we stored it with <code>use_state</code>, the only way to add a new value to the list would be to create a new <code>Vec</code> with the additional value, and put it in the state. This is expensive! We want to modify the existing <code>Vec</code> instead.</p>
- <p>Thankfully, there is another hook for that, <code>use_ref</code>! It is similar to <code>use_state</code>, but it lets you get a mutable reference to the contained data.</p>
- <p>Here's a simple example that keeps a list of events in a <code>use_ref</code>. We can acquire write access to the state with <code>.with_mut()</code>, and then just <code>.push</code> a new value to the state:</p>
- <pre><pre class="playground"><code class="language-rust edition2018">
- <span class="boring">#![allow(unused)]
- </span><span class="boring">fn main() {
- </span>fn App(cx: Scope) -> Element {
- let list = use_ref(cx, Vec::new);
- cx.render(rsx!(
- p { "Current list: {list.read():?}" }
- button {
- onclick: move |event| {
- list.with_mut(|list| list.push(event));
- },
- "Click me!"
- }
- ))
- }
- <span class="boring">}
- </span></code></pre></pre>
- <blockquote>
- <p>The return values of <code>use_state</code> and <code>use_ref</code> (<code>UseState</code> and <code>UseRef</code>, respectively) are in some ways similar to <a href="https://doc.rust-lang.org/std/cell/"><code>Cell</code></a> and <a href="https://doc.rust-lang.org/std/cell/struct.RefCell.html"><code>RefCell</code></a> – they provide interior mutability. However, these Dioxus wrappers also ensure that the component gets re-rendered whenever you change the state.</p>
- </blockquote>
- </main>
- <nav class="nav-wrapper" aria-label="Page navigation">
- <!-- Mobile navigation buttons -->
- <a rel="prev" href="../interactivity/event_handlers.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
- <i class="fa fa-angle-left"></i>
- </a>
- <a rel="next" href="../interactivity/user_input.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
- <i class="fa fa-angle-right"></i>
- </a>
- <div style="clear: both"></div>
- </nav>
- </div>
- </div>
- <nav class="nav-wide-wrapper" aria-label="Page navigation">
- <a rel="prev" href="../interactivity/event_handlers.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
- <i class="fa fa-angle-left"></i>
- </a>
- <a rel="next" href="../interactivity/user_input.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
- <i class="fa fa-angle-right"></i>
- </a>
- </nav>
- </div>
- <script type="text/javascript">
- window.playground_line_numbers = true;
- </script>
- <script type="text/javascript">
- window.playground_copyable = true;
- </script>
- <script src="../ace.js" type="text/javascript" charset="utf-8"></script>
- <script src="../editor.js" type="text/javascript" charset="utf-8"></script>
- <script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
- <script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
- <script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
- <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
- <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
- <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
- <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
- <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
- <script src="../book.js" type="text/javascript" charset="utf-8"></script>
- <!-- Custom JS scripts -->
- </body>
- </html>
|