Fix the router and stub out a number of crates to get compiling

This commit is contained in:
Jonathan Kelley committed 2024-01-13 20:51:37 -08:00
1 parent 4c6e515da4
commit fae0b08e61
226 files changed
+1057 -1482

No files matched your search

+10 -11
View File
@@ -1,6 +1,6 @@
//! Tracked and computed state in Dioxus
use dioxus_core::{ScopeId, ScopeState};
use dioxus_core::{ScopeId};
use slab::Slab;
use std::{
cell::{RefCell, RefMut},
@@ -18,8 +18,8 @@ use std::{
/// use dioxus::prelude::*;
///
/// #[component]
/// fn Parent(cx: Scope) -> Element {
/// let count = use_tracked_state(cx, || 0);
/// fn Parent() -> Element {
/// let count = use_tracked_state(|| 0);
///
/// render! {
/// Child {
@@ -29,8 +29,8 @@ use std::{
/// }
///
/// #[component]
/// fn Child(cx: Scope, count: Tracked<usize>) -> Element {
/// let less_than_five = use_selector(cx, count, |count| *count < 5);
/// fn Child(count: Tracked<usize>) -> Element {
/// let less_than_five = use_selector(count, |count| *count < 5);
///
/// render! {
/// "{less_than_five}"
@@ -38,10 +38,10 @@ use std::{
/// }
/// ```
#[must_use]
pub fn use_tracked_state<T: 'static>(cx: &ScopeState, init: impl FnOnce() -> T) -> &Tracked<T> {
pub fn use_tracked_state<T: 'static>(nit: impl FnOnce() -> T) -> &Tracked<T> {
cx.use_hook(|| {
let init = init();
Tracked::new(cx, init)
Tracked::new(init)
})
}
@@ -63,7 +63,7 @@ impl<I: PartialEq> PartialEq for Tracked<I> {
impl<I> Tracked<I> {
/// Create a new tracked state
pub fn new(cx: &ScopeState, state: I) -> Self {
pub fn new(, state: I) -> Self {
let subscribers = std::rc::Rc::new(std::cell::RefCell::new(Slab::new()));
Self {
state: Rc::new(RefCell::new(state)),
@@ -162,8 +162,7 @@ impl<I> Drop for Tracker<I> {
}
#[must_use = "Consider using the `use_effect` hook to rerun an effect whenever the tracked state changes if you don't need the result of the computation"]
pub fn use_selector<I: 'static, O: Clone + PartialEq + 'static>(
cx: &ScopeState,
pub fn use_selector<I: 'static, O: Clone + PartialEq + 'static>
tracked: &Tracked<I>,
init: impl FnMut(&I) -> O + 'static,
) -> O {
@@ -189,7 +188,7 @@ impl<T, I> PartialEq for Selector<T, I> {
impl<T: Clone + PartialEq, I> Selector<T, I> {
/// Read the Selector state and subscribe to updates
pub fn use_state(&self, cx: &ScopeState) -> T {
pub fn use_state(&self, ) -> T {
cx.use_hook(|| {
let id = cx.scope_id();
self.subscribers.borrow_mut().insert(id);
+1 -1
View File
@@ -18,7 +18,7 @@
/// # }
/// # fn Component(cx: Scope<Props>) -> Element {
///
/// let (data) = use_ref(cx, || {});
/// let (data) = use_ref(|| {});
///
/// let handle_thing = move |_| {
/// to_owned![data, cx.props.prop];
+4 -4
View File
@@ -25,7 +25,7 @@ macro_rules! use_callback {
};
}
pub fn use_callback<T, R, F>(cx: &ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + '_
pub fn use_callback<T, R, F>(, make: impl FnOnce() -> R) -> impl FnMut(T) + '_
where
R: FnMut(T) -> F + 'static,
F: Future<Output = ()> + 'static,
@@ -35,14 +35,14 @@ where
move |evt| cx.spawn(hook(evt))
}
fn _it_works(cx: &ScopeState) {
let _p = use_callback(cx, || {
fn _it_works() {
let _p = use_callback(|| {
|()| async {
//
}
});
// let p = use_callback!(cx, || |evt| async {
// let p = use_callback!(|| |evt| async {
// //
// });
}
+2 -2
View File
@@ -16,7 +16,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(|| HashMap::new());
set_map({
let mut newmap = map.clone();
newmap.set(key, value);
@@ -37,7 +37,7 @@ uses the same memoization on top of the use_context API.
Here's a fully-functional todo app using the use_map API:
```rust
static TodoList: Component = |cx| {
let todos = use_map(cx, || HashMap::new());
let todos = use_map(|| HashMap::new());
let input = use_ref(|| None);
cx.render(rsx!{
+5 -6
View File
@@ -11,8 +11,8 @@ use dioxus_core::prelude::*;
/// ```rust, ignore
/// struct ComplexData(i32);
///
/// fn Component(cx: Scope) -> Element {
/// let id = use_const(cx, || ComplexData(100));
/// fn Component() -> Element {
/// let id = use_const(|| ComplexData(100));
///
/// cx.render(rsx! {
/// div { "{id.0}" }
@@ -20,8 +20,7 @@ use dioxus_core::prelude::*;
/// }
/// ```
#[must_use]
pub fn use_const<T: 'static>(
cx: &ScopeState,
pub fn use_const<T: 'static>
initial_state_fn: impl FnOnce() -> T,
) -> &UseConst<T> {
cx.use_hook(|| UseConst {
@@ -64,8 +63,8 @@ impl<T> std::ops::Deref for UseConst<T> {
fn use_const_makes_sense() {
#[allow(unused)]
fn app(cx: Scope) -> Element {
let const_val = use_const(cx, || vec![0, 1, 2, 3]);
fn app() -> Element {
let const_val = use_const(|| vec![0, 1, 2, 3]);
assert!(const_val[0] == 0);
+2 -2
View File
@@ -4,14 +4,14 @@ use dioxus_core::ScopeState;
///
/// Does not regenerate the value if the value is changed at the parent.
#[must_use]
pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> {
pub fn use_context<T: 'static + Clone>() -> Option<&T> {
cx.use_hook(|| cx.consume_context::<T>()).as_ref()
}
/// Provide some context via the tree and return a reference to it
///
/// Once the context has been provided, it is immutable. Mutations should be done via interior mutability.
pub fn use_context_provider<T: 'static + Clone>(cx: &ScopeState, f: impl FnOnce() -> T) -> &T {
pub fn use_context_provider<T: 'static + Clone>(f: impl FnOnce() -> T) -> &T {
cx.use_hook(|| {
let val = f();
cx.provide_context(val.clone());
+7 -7
View File
@@ -46,7 +46,7 @@ use std::future::Future;
/// Stop,
/// }
///
/// let chat_client = use_coroutine(cx, |mut rx: UnboundedReceiver<Action>| async move {
/// let chat_client = use_coroutine(|mut rx: UnboundedReceiver<Action>| async move {
/// while let Some(action) = rx.next().await {
/// match action {
/// Action::Start => {}
@@ -63,7 +63,7 @@ use std::future::Future;
/// }
/// })
/// ```
pub fn use_coroutine<M, G, F>(cx: &ScopeState, init: G) -> &Coroutine<M>
pub fn use_coroutine<M, G, F>(nit: G) -> &Coroutine<M>
where
M: 'static,
G: FnOnce(UnboundedReceiver<M>) -> F,
@@ -80,7 +80,7 @@ where
///
/// See the docs for [`use_coroutine`] for more details.
#[must_use]
pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&Coroutine<M>> {
pub fn use_coroutine_handle<M: 'static>() -> Option<&Coroutine<M>> {
cx.use_hook(|| cx.consume_context::<Coroutine<M>>())
.as_ref()
}
@@ -128,16 +128,16 @@ mod tests {
use futures_channel::mpsc::unbounded;
use futures_util::StreamExt;
fn app(cx: Scope, name: String) -> Element {
let task = use_coroutine(cx, |mut rx: UnboundedReceiver<i32>| async move {
fn app(name: String) -> Element {
let task = use_coroutine(|mut rx: UnboundedReceiver<i32>| async move {
while let Some(msg) = rx.next().await {
println!("got message: {msg}");
}
});
let task2 = use_coroutine(cx, view_task);
let task2 = use_coroutine(view_task);
let task3 = use_coroutine(cx, |rx| complex_task(rx, 10));
let task3 = use_coroutine(|rx| complex_task(rx, 10));
todo!()
}
+12 -12
View File
@@ -26,11 +26,11 @@ use crate::UseFutureDep;
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// #[component]
/// fn Profile(cx: Scope, id: usize) -> Element {
/// let name = use_state(cx, || None);
/// fn Profile(id: usize) -> Element {
/// let name = use_state(|| None);
///
/// // Only fetch the user data when the id changes.
/// use_effect(cx, (id,), |(id,)| {
/// use_effect((id,), |(id,)| {
/// to_owned![name];
/// async move {
/// let user = fetch_user(id).await;
@@ -39,7 +39,7 @@ use crate::UseFutureDep;
/// });
///
/// // Only fetch the user data when the id changes.
/// use_effect(cx, (id,), |(id,)| {
/// use_effect((id,), |(id,)| {
/// to_owned![name];
/// async move {
/// let user = fetch_user(id).await;
@@ -56,11 +56,11 @@ use crate::UseFutureDep;
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// fn App() -> Element {
/// render!(Profile { id: 0 })
/// }
/// ```
pub fn use_effect<T, R, D>(cx: &ScopeState, dependencies: D, future: impl FnOnce(D::Out) -> R)
pub fn use_effect<T, R, D>(, dependencies: D, future: impl FnOnce(D::Out) -> R)
where
D: UseFutureDep,
R: UseEffectReturn<T>,
@@ -108,14 +108,14 @@ type UseEffectCleanup = Rc<RefCell<Option<Box<dyn FnOnce()>>>>;
/// Something that can be returned from a `use_effect` hook.
pub trait UseEffectReturn<T> {
fn apply(self, oncleanup: UseEffectCleanup, cx: &ScopeState) -> Task;
fn apply(self, oncleanup: UseEffectCleanup, ) -> Task;
}
impl<T> UseEffectReturn<()> for T
where
T: Future<Output = ()> + 'static,
{
fn apply(self, _: UseEffectCleanup, cx: &ScopeState) -> Task {
fn apply(self, _: UseEffectCleanup, ) -> Task {
cx.push_future(self)
}
}
@@ -127,7 +127,7 @@ where
T: Future<Output = F> + 'static,
F: FnOnce() + 'static,
{
fn apply(self, oncleanup: UseEffectCleanup, cx: &ScopeState) -> Task {
fn apply(self, oncleanup: UseEffectCleanup, ) -> Task {
cx.push_future(async move {
let cleanup = self.await;
*oncleanup.borrow_mut() = Some(Box::new(cleanup) as Box<dyn FnOnce()>);
@@ -154,17 +154,17 @@ mod tests {
fn app(cx: Scope<MyProps>) -> Element {
// should only ever run once
use_effect(cx, (), |_| async move {
use_effect((), |_| async move {
//
});
// runs when a is changed
use_effect(cx, (&cx.props.a,), |(a,)| async move {
use_effect((&cx.props.a,), |(a,)| async move {
//
});
// runs when a or b is changed
use_effect(cx, (&cx.props.a, &cx.props.b), |(a, b)| async move {
use_effect((&cx.props.a, &cx.props.b), |(a, b)| async move {
//
});
+8 -9
View File
@@ -17,8 +17,7 @@ use crate::{use_state, UseState};
/// will be canceled before the new one is started.
///
/// - dependencies: a tuple of references to values that are PartialEq + Clone
pub fn use_future<T, F, D>(
cx: &ScopeState,
pub fn use_future<T, F, D>
dependencies: D,
future: impl FnOnce(D::Out) -> F,
) -> &UseFuture<T>
@@ -27,7 +26,7 @@ where
F: Future<Output = T> + 'static,
D: UseFutureDep,
{
let val = use_state(cx, || None);
let val = use_state(|| None);
let state = cx.use_hook(move || UseFuture {
update: cx.schedule_update(),
@@ -95,7 +94,7 @@ impl<T> UseFuture<T> {
}
/// Forcefully cancel a future
pub fn cancel(&self, cx: &ScopeState) {
pub fn cancel(&self, ) {
if let Some(task) = self.task.take() {
cx.remove_future(task);
}
@@ -261,22 +260,22 @@ mod tests {
async fn app(cx: Scope<'_, MyProps>) -> Element {
// should only ever run once
let fut = use_future(cx, (), |_| async move {});
let fut = use_future((), |_| async move {});
// runs when a is changed
let fut = use_future(cx, (&cx.props.a,), |(a,)| async move {});
let fut = use_future((&cx.props.a,), |(a,)| async move {});
// runs when a or b is changed
let fut = use_future(cx, (&cx.props.a, &cx.props.b), |(a, b)| async move { 123 });
let fut = use_future((&cx.props.a, &cx.props.b), |(a, b)| async move { 123 });
let a = use_future!(cx, || async move {
let a = use_future!(|| async move {
// do the thing!
});
let b = &123;
let c = &123;
let a = use_future!(cx, |b, c| async move {
let a = use_future!(|b, c| async move {
let a = b + c;
let blah = "asd";
});
+4 -4
View File
@@ -13,8 +13,8 @@ use crate::UseFutureDep;
/// # use dioxus::prelude::*;
///
/// #[component]
/// fn Calculator(cx: Scope, number: usize) -> Element {
/// let bigger_number = use_memo(cx, (number,), |(number,)| {
/// fn Calculator(number: usize) -> Element {
/// let bigger_number = use_memo((number,), |(number,)| {
/// // This will only be calculated when `number` has changed.
/// number * 100
/// });
@@ -24,12 +24,12 @@ use crate::UseFutureDep;
/// }
///
/// #[component]
/// fn App(cx: Scope) -> Element {
/// fn App() -> Element {
/// render!(Calculator { number: 0 })
/// }
/// ```
#[must_use = "Consider using `use_effect` to run rerun a callback when dependencies change"]
pub fn use_memo<T, D>(cx: &ScopeState, dependencies: D, callback: impl FnOnce(D::Out) -> T) -> &T
pub fn use_memo<T, D>(, dependencies: D, callback: impl FnOnce(D::Out) -> T) -> &T
where
T: 'static,
D: UseFutureDep,
+1 -1
View File
@@ -7,7 +7,7 @@ use std::future::Future;
/// This is just [`use_effect`](crate::use_effect), but with no dependencies.
/// If you have no dependencies, it's recommended to use this, not just because it's more readable,
/// but also because it's a tiny bit more efficient.
pub fn use_on_create<T, F>(cx: &ScopeState, future: impl FnOnce() -> F)
pub fn use_on_create<T, F>(future: impl FnOnce() -> F)
where
T: 'static,
F: Future<Output = T> + 'static,
+7 -7
View File
@@ -4,7 +4,7 @@ This is deprecated because of the introduction of `use_on_create` which is bette
The reason why `use_on_create` is not `use_on_mount` is because of potential confusion with `dioxus::events::onmounted`."
)]
pub fn use_on_unmount<D: FnOnce() + 'static>(cx: &dioxus_core::ScopeState, destroy: D) {
use_on_destroy(cx, destroy);
use_on_destroy(destroy);
}
/// Creates a callback that will be run before the component is removed.
@@ -15,8 +15,8 @@ pub fn use_on_unmount<D: FnOnce() + 'static>(cx: &dioxus_core::ScopeState, destr
/// ```rust
/// use dioxus::prelude::*;
///
/// fn app(cx: Scope) -> Element {
/// let state = use_state(cx, || true);
/// fn app() -> Element {
/// let state = use_state(|| true);
/// render! {
/// for _ in 0..100 {
/// h1 {
@@ -37,9 +37,9 @@ pub fn use_on_unmount<D: FnOnce() + 'static>(cx: &dioxus_core::ScopeState, destr
/// }
/// }
///
/// fn child_component(cx: Scope) -> Element {
/// let original_scroll_position = use_state(cx, || 0.0);
/// use_effect(cx, (), move |_| {
/// fn child_component() -> Element {
/// let original_scroll_position = use_state(|| 0.0);
/// use_effect((), move |_| {
/// to_owned![original_scroll_position];
/// async move {
/// let window = web_sys::window().unwrap();
@@ -50,7 +50,7 @@ pub fn use_on_unmount<D: FnOnce() + 'static>(cx: &dioxus_core::ScopeState, destr
/// }
/// });
///
/// use_on_destroy(cx, {
/// use_on_destroy({
/// to_owned![original_scroll_position];
/// /// restore scroll to the top of the page
/// move || {
+1 -1
View File
@@ -111,7 +111,7 @@ use std::{
/// })
/// ```
#[must_use]
pub fn use_ref<T: 'static>(cx: &ScopeState, initialize_refcell: impl FnOnce() -> T) -> &UseRef<T> {
pub fn use_ref<T: 'static>(nitialize_refcell: impl FnOnce() -> T) -> &UseRef<T> {
let hook = cx.use_hook(|| UseRef {
update: cx.schedule_update(),
value: Rc::new(RefCell::new(initialize_refcell())),
+1 -1
View File
@@ -1,7 +1,7 @@
use dioxus_core::ScopeState;
///
pub fn use_root_context<T: 'static + Clone>(cx: &ScopeState, new: impl FnOnce() -> T) -> &T {
pub fn use_root_context<T: 'static + Clone>(, new: impl FnOnce() -> T) -> &T {
cx.use_hook(|| {
cx.consume_context::<T>()
.unwrap_or_else(|| cx.provide_root_context(new()))
+13 -13
View File
@@ -1,5 +1,5 @@
use self::error::{UseSharedStateError, UseSharedStateResult};
use dioxus_core::{ScopeId, ScopeState};
use dioxus_core::ScopeId;
use std::{collections::HashSet, rc::Rc, sync::Arc};
#[cfg(debug_assertions)]
@@ -104,7 +104,7 @@ impl<T> ProvidedStateInner<T> {
/// ```rust
/// # use dioxus::prelude::*;
/// #
/// # fn app(cx: Scope) -> Element {
/// # fn app() -> Element {
/// # render! {
/// # Parent{}
/// # }
@@ -117,9 +117,9 @@ impl<T> ProvidedStateInner<T> {
/// }
///
/// // Provider
/// fn Parent<'a>(cx: Scope<'a>) -> Element<'a> {
/// use_shared_state_provider(cx, || Theme::Dark);
/// let theme = use_shared_state::<Theme>(cx).unwrap();
/// fn Parent<'a>(cx: Scope<'a>) -> Element {
/// use_shared_state_provider(|| Theme::Dark);
/// let theme = use_shared_state::<Theme>().unwrap();
///
/// render! {
/// button{
@@ -137,8 +137,8 @@ impl<T> ProvidedStateInner<T> {
/// }
///
/// // Consumer
/// fn Child<'a>(cx: Scope<'a>) -> Element<'a> {
/// let theme = use_shared_state::<Theme>(cx).unwrap();
/// fn Child<'a>(cx: Scope<'a>) -> Element {
/// let theme = use_shared_state::<Theme>().unwrap();
/// let current_theme = *theme.read();
///
/// render! {
@@ -160,7 +160,7 @@ impl<T> ProvidedStateInner<T> {
///
/// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified.
#[must_use]
pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<&UseSharedState<T>> {
pub fn use_shared_state<T: 'static>() -> Option<&UseSharedState<T>> {
let state_owner: &mut Option<UseSharedStateOwner<T>> = &mut *cx.use_hook(move || {
let scope_id = cx.scope_id();
let root = cx.consume_context::<ProvidedState<T>>()?;
@@ -330,7 +330,7 @@ impl<T> PartialEq for UseSharedState<T> {
/// ```rust
/// # use dioxus::prelude::*;
/// #
/// # fn app(cx: Scope) -> Element {
/// # fn app() -> Element {
/// # render! {
/// # Parent{}
/// # }
@@ -343,9 +343,9 @@ impl<T> PartialEq for UseSharedState<T> {
/// }
///
/// // Provider
/// fn Parent<'a>(cx: Scope<'a>) -> Element<'a> {
/// use_shared_state_provider(cx, || Theme::Dark);
/// let theme = use_shared_state::<Theme>(cx).unwrap();
/// fn Parent<'a>(cx: Scope<'a>) -> Element {
/// use_shared_state_provider(|| Theme::Dark);
/// let theme = use_shared_state::<Theme>().unwrap();
///
/// render! {
/// button{
@@ -362,7 +362,7 @@ impl<T> PartialEq for UseSharedState<T> {
/// }
/// }
/// ```
pub fn use_shared_state_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) {
pub fn use_shared_state_provider<T: 'static>(f: impl FnOnce() -> T) {
cx.use_hook(|| {
let state: ProvidedState<T> = Rc::new(RefCell::new(ProvidedStateInner {
value: f(),
+16 -17
View File
@@ -19,7 +19,7 @@ use std::{
///
/// ```ignore
/// const Example: Component = |cx| {
/// let count = use_state(cx, || 0);
/// let count = use_state(|| 0);
///
/// cx.render(rsx! {
/// div {
@@ -31,8 +31,7 @@ use std::{
/// }
/// ```
#[must_use]
pub fn use_state<T: 'static>(
cx: &ScopeState,
pub fn use_state<T: 'static>
initial_state_fn: impl FnOnce() -> T,
) -> &UseState<T> {
let hook = cx.use_hook(move || {
@@ -92,8 +91,8 @@ impl<T: 'static> UseState<T> {
/// An async context might need to know the current value:
///
/// ```rust, ignore
/// fn component(cx: Scope) -> Element {
/// let count = use_state(cx, || 0);
/// fn component() -> Element {
/// let count = use_state(|| 0);
/// cx.spawn({
/// let set_count = count.to_owned();
/// async move {
@@ -119,8 +118,8 @@ impl<T: 'static> UseState<T> {
/// A component might require an `Rc<dyn Fn(T)>` as an input to set a value.
///
/// ```rust, ignore
/// fn component(cx: Scope) -> Element {
/// let value = use_state(cx, || 0);
/// fn component() -> Element {
/// let value = use_state(|| 0);
///
/// rsx!{
/// Component {
@@ -144,8 +143,8 @@ impl<T: 'static> UseState<T> {
/// ```rust, ignore
/// # use dioxus_core::prelude::*;
/// # use dioxus_hooks::*;
/// fn component(cx: Scope) -> Element {
/// let value = use_state(cx, || 0);
/// fn component() -> Element {
/// let value = use_state(|| 0);
///
/// // to increment the value
/// value.modify(|v| v + 1);
@@ -185,8 +184,8 @@ impl<T: 'static> UseState<T> {
/// ```rust, ignore
/// # use dioxus_core::prelude::*;
/// # use dioxus_hooks::*;
/// fn component(cx: Scope) -> Element {
/// let value = use_state(cx, || 0);
/// fn component() -> Element {
/// let value = use_state(|| 0);
///
/// let as_rc = value.get();
/// assert_eq!(as_rc.as_ref(), &0);
@@ -207,8 +206,8 @@ impl<T: 'static> UseState<T> {
/// Mark the component that create this [`UseState`] as dirty, forcing it to re-render.
///
/// ```rust, ignore
/// fn component(cx: Scope) -> Element {
/// let count = use_state(cx, || 0);
/// fn component() -> Element {
/// let count = use_state(|| 0);
/// cx.spawn({
/// let count = count.to_owned();
/// async move {
@@ -238,7 +237,7 @@ impl<T: Clone> UseState<T> {
/// # Examples
///
/// ```rust, ignore
/// let val = use_state(cx, || 0);
/// let val = use_state(|| 0);
///
/// val.with_mut(|v| *v = 1);
/// ```
@@ -270,7 +269,7 @@ impl<T: Clone> UseState<T> {
/// # Examples
///
/// ```rust, ignore
/// let val = use_state(cx, || 0);
/// let val = use_state(|| 0);
///
/// *val.make_mut() += 1;
/// ```
@@ -493,8 +492,8 @@ impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for UseState<T> {
#[test]
fn api_makes_sense() {
#[allow(unused)]
fn app(cx: Scope) -> Element {
let val = use_state(cx, || 0);
fn app() -> Element {
let val = use_state(|| 0);
val.set(0);
val.modify(|v| v + 1);