wip: move some examples around

This commit is contained in:
Jonathan Kelley 2021-07-07 16:19:10 -04:00
parent cca7c5fc3a
commit 98a09339fd
70 changed files with 111 additions and 117 deletions

View file

@ -60,3 +60,4 @@ wasm
7ns
attr
derefed
Tokio

View file

@ -12,7 +12,7 @@ Your component today might look something like this:
```rust
fn Comp(cx: Context<()>) -> VNode {
let (title, set_title) = use_state(&cx, || "Title".to_string());
let (title, set_title) = use_state(cx, || "Title".to_string());
cx.render(rsx!{
input {
value: title,
@ -26,7 +26,7 @@ This component is fairly straightforward - the input updates its own value on ev
```rust
fn Comp(cx: Context<()>) -> VNode {
let (title, set_title) = use_state(&cx, || "Title".to_string());
let (title, set_title) = use_state(cx, || "Title".to_string());
cx.render(rsx!{
div {
input {

View file

@ -16,7 +16,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (state, set_state) = use_state_classic(&cx, || 0);
let (state, set_state) = use_state_classic(cx, || 0);
cx.render(rsx! {
div {
section { class: "py-12 px-4 text-center"

View file

@ -28,9 +28,9 @@ enum Operator {
}
static App: FC<()> = |cx| {
let (cur_val, set_cur_val) = use_state_classic(&cx, || 0.0_f64);
let (operator, set_operator) = use_state_classic(&cx, || None as Option<Operator>);
let (display_value, set_display_value) = use_state_classic(&cx, || "0".to_string());
let (cur_val, set_cur_val) = use_state_classic(cx, || 0.0_f64);
let (operator, set_operator) = use_state_classic(cx, || None as Option<Operator>);
let (display_value, set_display_value) = use_state_classic(cx, || "0".to_string());
let clear_display = display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };

View file

@ -12,7 +12,7 @@ fn main() {
}
fn CustomA(cx: Context<()>) -> VNode {
let (val, set_val) = use_state_classic(&cx, || "abcdef".to_string() as String);
let (val, set_val) = use_state_classic(cx, || "abcdef".to_string() as String);
cx.render(rsx! {
div {

View file

@ -10,7 +10,7 @@ fn main() {
}
fn App(cx: Context<()>) -> VNode {
let cansee = use_state(&cx, || false);
let cansee = use_state(cx, || false);
rsx! { in cx,
div {
"Shadow of the child:"

View file

@ -28,8 +28,8 @@ type RowList = im_rc::HashMap<usize, Rc<str>, FxBuildHasher>;
// type RowList = im_rc::HashMap<usize, Rc<str>, nohash_hasher::BuildNoHashHasher<usize>>;
static App: FC<()> = |cx| {
let (items, set_items) = use_state_classic(&cx, || RowList::default());
let (selection, set_selection) = use_state_classic(&cx, || None as Option<usize>);
let (items, set_items) = use_state_classic(cx, || RowList::default());
let (selection, set_selection) = use_state_classic(cx, || None as Option<usize>);
let create_rendered_rows = move |from, num| move |_| set_items(create_row_list(from, num));

View file

@ -15,7 +15,7 @@ fn main() {
// this is a component
static Example: FC<()> = |cx| {
let (event, set_event) = use_state_classic(&cx, || None);
let (event, set_event) = use_state_classic(cx, || None);
let handler = move |evt| {
set_event(Some(evt));

View file

@ -13,7 +13,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (val, set_val) = use_state_classic(&cx, || "asd".to_string());
let (val, set_val) = use_state_classic(cx, || "asd".to_string());
cx.render(rsx! {
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
@ -51,7 +51,7 @@ static Example: FC<()> = |cx| {
};
static UserInput: FC<()> = |cx| {
let (val, set_val) = use_state_classic(&cx, || "asd".to_string());
let (val, set_val) = use_state_classic(cx, || "asd".to_string());
rsx! { in cx,
div { class: "mb-4"

View file

@ -10,7 +10,7 @@ fn main() {
}
static Example: FC<()> = |cx| {
let (name, set_name) = use_state_classic(&cx, || "...?");
let (name, set_name) = use_state_classic(cx, || "...?");
log::debug!("Running component....");

View file

@ -10,7 +10,7 @@ fn main() {
}
static Example: FC<()> = |cx| {
let (name, set_name) = use_state_classic(&cx, || "...?");
let (name, set_name) = use_state_classic(cx, || "...?");
cx.render(rsx! {
section { class: "py-12 px-4 text-center"
div { class: "w-full max-w-2xl mx-auto"

View file

@ -15,7 +15,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (contents, set_contents) = use_state_classic(&cx, || "asd");
let (contents, set_contents) = use_state_classic(cx, || "asd");
cx.render(rsx! {
div {

View file

@ -14,7 +14,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (contents, set_contents) = use_state_classic(&cx, || "asd");
let (contents, set_contents) = use_state_classic(cx, || "asd");
cx.render(rsx! {
div { class: "flex items-center justify-center flex-col"

View file

@ -27,9 +27,9 @@ pub struct TodoItem {
}
static App: FC<()> = |cx| {
let (draft, set_draft) = use_state_classic(&cx, || "".to_string());
let (filter, set_filter) = use_state_classic(&cx, || FilterState::All);
let todos = use_state(&cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
let todos = use_state(cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
cx.render(rsx!(
div {
id: "app"

View file

@ -28,7 +28,7 @@ struct ExampleProps {
}
static Example: FC<ExampleProps> = |cx| {
let name = use_state(&cx, move || cx.initial_name);
let name = use_state(cx, move || cx.initial_name);
cx.render(rsx! {
div {

View file

@ -26,9 +26,9 @@ pub struct TodoItem {
}
pub fn App(cx: Context<()>) -> VNode {
let (draft, set_draft) = use_state_classic(&cx, || "".to_string());
let (todos, set_todos) = use_state_classic(&cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
let (filter, set_filter) = use_state_classic(&cx, || FilterState::All);
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
let filtered_todos = todos.iter().filter(move |(id, item)| match filter {
FilterState::All => true,
@ -100,7 +100,7 @@ pub struct TodoEntryProps {
}
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
let (is_editing, set_is_editing) = use_state_classic(&cx, || false);
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
let contents = "";
let todo = TodoItem {
checked: false,

View file

@ -8,7 +8,7 @@ pub struct TodoEntryProps {
}
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> VNode {
let (is_editing, set_is_editing) = use_state(&cx, || false);
let (is_editing, set_is_editing) = use_state(cx, || false);
let todo = use_atom_family(&cx, &TODOS, cx.id);
cx.render(rsx! (

View file

@ -7,8 +7,8 @@ use crate::{
use dioxus_core::prelude::*;
pub fn TodoList(cx: Context<()>) -> VNode {
let (draft, set_draft) = use_state(&cx, || "".to_string());
let (todos, _) = use_state(&cx, || Vec::<TodoItem>::new());
let (draft, set_draft) = use_state(cx, || "".to_string());
let (todos, _) = use_state(cx, || Vec::<TodoItem>::new());
let filter = use_atom(&cx, &FILTER);
cx.render(rsx! {

View file

@ -54,9 +54,9 @@ pub fn App(cx: Context<()>) -> VNode {
}
pub fn TodoList(cx: Context<()>) -> VNode {
let (draft, set_draft) = use_state_classic(&cx, || "".to_string());
let (todos, set_todos) = use_state_classic(&cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
let (filter, set_filter) = use_state_classic(&cx, || FilterState::All);
let (draft, set_draft) = use_state_classic(cx, || "".to_string());
let (todos, set_todos) = use_state_classic(cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
let (filter, set_filter) = use_state_classic(cx, || FilterState::All);
cx.render(rsx! {
div {
@ -103,7 +103,7 @@ pub struct TodoEntryProps {
}
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
let (is_editing, set_is_editing) = use_state_classic(&cx, || false);
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
let contents = "";
let todo = TodoItem {
checked: false,

View file

@ -74,7 +74,7 @@ impl TodoManager {
}
pub fn TodoList(cx: Context<()>) -> VNode {
let draft = use_state(&cx, || "".to_string());
let draft = use_state(cx, || "".to_string());
let todos = use_read(&cx, &TODO_LIST);
let filter = use_read(&cx, &FILTER);
@ -118,7 +118,7 @@ pub struct TodoEntryProps {
}
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> VNode {
let (is_editing, set_is_editing) = use_state_classic(&cx, || false);
let (is_editing, set_is_editing) = use_state_classic(cx, || false);
let todo = use_read(&cx, &TODO_LIST).get(&cx.id).unwrap();
cx.render(rsx! (

View file

@ -19,9 +19,9 @@ enum Operator {
}
static App: FC<()> = |cx| {
let cur_val = use_state(&cx, || 0.0_f64);
let operator = use_state(&cx, || None as Option<Operator>);
let display_value = use_state(&cx, || "".to_string());
let cur_val = use_state(cx, || 0.0_f64);
let operator = use_state(cx, || None as Option<Operator>);
let display_value = use_state(cx, || "".to_string());
let clear_display = display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };

View file

@ -2,7 +2,7 @@ use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
let (g, set_g) = use_state_classic(&cx, || 0);
let (g, set_g) = use_state_classic(cx, || 0);
let v = (0..10).map(move |f| {
rsx!(li {
onclick: move |_| set_g(10)

View file

@ -23,7 +23,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let calc = use_model(&cx, || Calculator::new());
let calc = use_model(cx, || Calculator::new());
let clear_display = calc.display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };

View file

@ -3,13 +3,12 @@
//! The example from the README.md
use dioxus::prelude::*;
fn main() {
dioxus::web::launch(Example)
}
fn Example(cx: Context<()>) -> VNode {
let name = use_state(&cx, || "..?");
let name = use_state(cx, || "..?");
cx.render(rsx! {
h1 { "Hello, {name}" }
@ -17,21 +16,3 @@ fn Example(cx: Context<()>) -> VNode {
button { "?", onclick: move |_| name.set("Dioxus 🎉")}
})
}
static Example2: FC<()> = |cx| {
let (g, set_g) = use_state_classic(&cx, || 0);
let v = (0..10).map(|f| {
dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory| {
__cx.element(dioxus_elements::li)
.listeners([dioxus::events::on::onclick(__cx, move |_| set_g(10))])
.finish()
})
});
cx.render(dioxus::prelude::LazyNodes::new(
move |__cx: &NodeFactory| {
__cx.element(dioxus_elements::div)
.children([__cx.fragment_from_iter(v)])
.finish()
},
))
};

View file

@ -8,7 +8,7 @@ fn main() {}
use dioxus::prelude::*;
pub static ExampleReducer: FC<()> = |cx| {
let (state, reduce) = use_reducer(&cx, PlayerState::new, PlayerState::reduce);
let (state, reduce) = use_reducer(cx, PlayerState::new, PlayerState::reduce);
let is_playing = state.is_playing();

View file

@ -85,7 +85,7 @@ static AntipatternNestedFragments: FC<()> = |cx| {
/// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state`
/// merely places a new value in the queue and schedules the component for a future update.
static AntipaternRelyingOnSetState: FC<()> = |cx| {
let (state, set_state) = use_state_classic(&cx, || "Hello world");
let (state, set_state) = use_state_classic(cx, || "Hello world");
set_state("New state");
// This will return false! `state` will *still* be "Hello world"
assert!(state == &"New state");
@ -126,7 +126,7 @@ static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx| {
if cx.should_render_state {
// do not place a hook in the conditional!
// prefer to move it out of the conditional
let (state, set_state) = use_state_classic(&cx, || "hello world");
let (state, set_state) = use_state_classic(cx, || "hello world");
rsx!(in cx, div { "{state}" })
} else {
rsx!(in cx, div { "Not rendering state" })

View file

@ -7,9 +7,6 @@ use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
cx.render(rsx! {
div {
}
})
//
cx.render(rsx! {})
};

View file

@ -2,7 +2,7 @@ use dioxus::prelude::*;
fn main() {}
static Example: FC<()> = |cx| {
let (g, set_g) = use_state_classic(&cx, || 0);
let (g, set_g) = use_state_classic(cx, || 0);
let v = (0..10).map(|f| {
rsx! {
li {

View file

@ -11,7 +11,7 @@ fn main() {}
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
static ButtonList: FC<()> = |cx| {
let (name, set_name) = use_state_classic(&cx, || "...?");
let (name, set_name) = use_state_classic(cx, || "...?");
let names = ["jack", "jill", "john", "jane"]
.iter()

View file

@ -47,7 +47,7 @@ fn main() {
const NONE_ELEMENT: Option<()> = None;
use baller::Baller;
use dioxus_core::prelude::*;
use dioxus::prelude::*;
static Example: FC<()> = |cx| {
let formatting = "formatting!";

View file

@ -16,7 +16,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (count, set_count) = use_state_classic(&cx, || 0);
let (count, set_count) = use_state_classic(cx, || 0);
cx.render(rsx! {
div {

View file

@ -17,4 +17,4 @@
- [] Implement controlled inputs for select and textarea
- [] ...somehow... noderefs....
use_state(&cx, )
use_state(cx, )

View file

@ -39,7 +39,7 @@ impl Parse for HtmlRender {
return input.parse::<LitStr>()?.parse::<HtmlRender>();
}
// let cx: Ident = s.parse()?;
// let __cx: Ident = s.parse()?;
// s.parse::<Token![,]>()?;
// if elements are in an array, return a bumpalo::collections::Vec rather than a Node.
let kind = if input.peek(token::Bracket) {
@ -64,8 +64,8 @@ impl ToTokens for HtmlRender {
// create a lazy tree that accepts a bump allocator
let final_tokens = quote! {
dioxus::prelude::LazyNodes::new(move |cx| {
let bump = &cx.bump();
dioxus::prelude::LazyNodes::new(move |__cx| {
let bump = __cx.bump();
#new_toks
})
@ -152,16 +152,18 @@ struct Element {
impl ToTokens for ToToksCtx<&Element> {
fn to_tokens(&self, tokens: &mut TokenStream2) {
// let cx = self.cx;
let name = &self.inner.name.to_string();
// let __cx = self.__cx;
let name = &self.inner.name;
// let name = &self.inner.name.to_string();
tokens.append_all(quote! {
dioxus::builder::ElementBuilder::new(cx, #name)
__cx.element(dioxus_elements::#name)
// dioxus::builder::ElementBuilder::new( #name)
});
for attr in self.inner.attrs.iter() {
self.recurse(attr).to_tokens(tokens);
}
if is_valid_svg_tag(name) {
if is_valid_svg_tag(&name.to_string()) {
tokens.append_all(quote! {
.namespace(Some("http://www.w3.org/2000/svg"))
});

View file

@ -18,7 +18,6 @@ use syn::{
pub enum AmbiguousElement {
Element(Element),
Component(Component),
Fragment(Fragment),
}
impl Parse for AmbiguousElement {
@ -76,7 +75,6 @@ impl ToTokens for AmbiguousElement {
match self {
AmbiguousElement::Element(el) => el.to_tokens(tokens),
AmbiguousElement::Component(comp) => comp.to_tokens(tokens),
AmbiguousElement::Fragment(frag) => frag.to_tokens(tokens),
}
}
}

View file

@ -133,14 +133,17 @@ impl ToTokens for Component {
let childs = &self.children;
let children = quote! {
ChildrenList::new(__cx)
#( .add_child(#childs) )*
.finish()
[ #( #childs ),* ]
};
// ChildrenList::new(__cx)
// #( .add_child(#childs) )*
// .finish()
// ChildrenList::new(__cx)
// #( .add_child(#childs) )*
// .finish()
tokens.append_all(quote! {
dioxus::builder::virtual_child(
__cx,
__cx.virtual_child(
#name,
#builder,
#key_token,

View file

@ -86,13 +86,13 @@ impl ToTokens for RsxRender {
match &self.custom_context {
// The `in cx` pattern allows directly rendering
Some(ident) => out_tokens.append_all(quote! {
#ident.render(dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory|{
#ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
#inner
}))
}),
// Otherwise we just build the LazyNode wrapper
None => out_tokens.append_all(quote! {
dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory|{
dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
#inner
})
}),

View file

@ -150,7 +150,7 @@ pub mod on {
$(
$(#[$method_attr])*
pub fn $name<'a>(
c: &'_ NodeFactory<'a>,
c: NodeFactory<'a>,
callback: impl Fn($wrapper) + 'a,
) -> Listener<'a> {
let bump = &c.bump();

View file

@ -23,7 +23,7 @@ use std::{
/// Usage:
/// ```ignore
/// static Example: FC<()> = |cx| {
/// let (counter, set_counter) = use_state(&cx, || 0);
/// let (counter, set_counter) = use_state(cx, || 0);
/// let increment = |_| set_couter(counter + 1);
/// let decrement = |_| set_couter(counter + 1);
///
@ -145,7 +145,7 @@ impl<'a, T: 'static + Display> std::fmt::Display for UseState<T> {
/// Usage:
/// ```ignore
/// static Example: FC<()> = |cx| {
/// let (counter, set_counter) = use_state(&cx, || 0);
/// let (counter, set_counter) = use_state(cx, || 0);
/// let increment = |_| set_couter(counter + 1);
/// let decrement = |_| set_couter(counter + 1);
///

View file

@ -620,23 +620,17 @@ where
}
}
// impl IntoVNode<'_> for () {
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
// todo!();
// VNode::Suspended {
// real: Cell::new(RealDomNode::empty()),
// }
// }
// }
impl IntoVNode<'_> for () {
fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
cx.fragment_from_iter(None as Option<VNode>)
}
}
// impl IntoVNode<'_> for Option<()> {
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
// todo!();
// VNode::Suspended {
// real: Cell::new(RealDomNode::empty()),
// }
// }
// }
impl IntoVNode<'_> for Option<()> {
fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
cx.fragment_from_iter(None as Option<VNode>)
}
}
/// Construct a text VNode.
///
@ -717,8 +711,6 @@ pub fn virtual_child<'a, T: Properties + 'a>(
VNode::Component(
cx.bump()
.alloc(crate::nodes::VComponent::new(&cx, f, props, key, children)),
// cx.bump()
// .alloc(crate::nodes::VComponent::new(f, props, key)),
)
}
@ -786,6 +778,26 @@ impl<'a> NodeFactory<'a> {
}))
}
pub fn virtual_child<T: Properties + 'a, C>(
&self,
f: FC<T>,
props: T,
key: Option<&'a str>, // key: NodeKey<'a>,
children: C,
) -> VNode<'a>
where
C: 'a + AsRef<[VNode<'a>]>,
{
let children: &'a C = self.bump().alloc(children);
VNode::Component(self.bump().alloc(crate::nodes::VComponent::new(
self,
f,
props,
key,
children.as_ref(),
)))
}
pub fn fragment_from_iter(
self,
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,

View file

@ -25,7 +25,7 @@ fn main() {
}
static App: FC<()> = |cx| {
let (url, set_url) = use_state(&cx, || "");
let (url, set_url) = use_state(cx, || "");
let body = match *url {
"community" => rsx!(in cx, Community {}),

View file

@ -34,7 +34,7 @@ enum LightState {
Red,
}
static HelloMessage: FC<()> = |cx| {
let (color, set_color) = use_state(&cx, || LightState::Green);
let (color, set_color) = use_state(cx, || LightState::Green);
let title = match color {
Green => "Green means go",

View file

@ -20,7 +20,7 @@ This is moderately efficient because the fields of the map are moved, but the da
However, if you used similar approach with Dioxus:
```rust
let (map, set_map) = use_state(&cx, || HashMap::new());
let (map, set_map) = use_state(cx, || HashMap::new());
set_map({
let mut newmap = map.clone();
newmap.set(key, value);

View file

@ -29,7 +29,7 @@ mod client {
static APP: FC<()> = |cx| {
todo!()
// let (selected_stream, set_stream) = use_state(&cx, || SelectedStream::Football);
// let (selected_stream, set_stream) = use_state(cx, || SelectedStream::Football);
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });

View file

@ -29,7 +29,7 @@ mod client {
static APP: FC<()> = |cx| {
todo!()
// let (selected_stream, set_stream) = use_state(&cx, || SelectedStream::Football);
// let (selected_stream, set_stream) = use_state(cx, || SelectedStream::Football);
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });

View file

@ -9,7 +9,7 @@ Dioxus-webview is an attempt at making a simpler "Tauri" where creating desktop
#[async_std::main]
async fn main() {
dioxus_webview::new(|cx| {
let (count, set_count) = use_state(&cx, || 0);
let (count, set_count) = use_state(cx, || 0);
cx.render(html! {
<div>
<h1> "Dioxus Desktop Demo" </h1>
@ -44,4 +44,4 @@ By bridging the native process, desktop apps can access full multithreading powe
Dioxus-desktop is a pure liveview application where all of the state and event handlers are proxied through the liveview and into the native process. For pure server-based liveview, this would normally be too slow (in both render performance and latency), but because the VDom is local, desktop apps are just as fast as Electron.
Dioxus-desktop leverages dioxus-liveview under the hood, but with convenience wrappers around setting up the VDom bridge, proxying events, and serving the initial WebSys-Renderer. The backend is served by Tide, so an async runtime _is_ needed - we recommend async-std in tokio mode.
Dioxus-desktop leverages dioxus-liveview under the hood, but with convenience wrappers around setting up the VDom bridge, proxying events, and serving the initial WebSys-Renderer. The backend is served by Tide, so an async runtime _is_ needed - we recommend async-std in Tokio mode.

View file

@ -94,7 +94,7 @@
//!
//! ```
//! static Example: FC<()> = |cx| {
//! let (val, set_val) = use_state(&cx, || 0);
//! let (val, set_val) = use_state(cx, || 0);
//! cx.render(rsx!(
//! button { onclick: move |_| set_val(val + 1) }
//! ))