feat: re-unify set_state

This commit is contained in:
Jonathan Kelley 2022-03-01 02:50:03 -05:00
parent 3928856a9b
commit 6c3f5195f4
16 changed files with 199 additions and 136 deletions

View file

@ -18,20 +18,16 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (display_value, set_display_value) = use_state(&cx, || String::from("0"));
let val = use_state(&cx, || String::from("0"));
let input_digit = move |num: u8| {
if display_value == "0" {
set_display_value(String::new());
if val.get() == "0" {
val.set(String::new());
}
set_display_value
.make_mut()
.push_str(num.to_string().as_str());
val.make_mut().push_str(num.to_string().as_str());
};
let input_operator = move |key: &str| {
set_display_value.make_mut().push_str(key);
};
let input_operator = move |key: &str| val.make_mut().push_str(key);
cx.render(rsx!(
style { [include_str!("./assets/calculator.css")] }
@ -54,34 +50,34 @@ fn app(cx: Scope) -> Element {
KeyCode::Num8 => input_digit(8),
KeyCode::Num9 => input_digit(9),
KeyCode::Backspace => {
if !display_value.len() != 0 {
set_display_value.make_mut().pop();
if !val.len() != 0 {
val.make_mut().pop();
}
}
_ => {}
},
div { class: "calculator-display", [display_value.to_string()] }
div { class: "calculator-display", [val.to_string()] }
div { class: "calculator-keypad",
div { class: "input-keys",
div { class: "function-keys",
button {
class: "calculator-key key-clear",
onclick: move |_| {
set_display_value(String::new());
if !display_value.is_empty(){
set_display_value("0".into());
val.set(String::new());
if !val.is_empty(){
val.set("0".into());
}
},
[if display_value.is_empty() { "C" } else { "AC" }]
[if val.is_empty() { "C" } else { "AC" }]
}
button {
class: "calculator-key key-sign",
onclick: move |_| {
let temp = calc_val(display_value.clone());
let temp = calc_val(val.as_str());
if temp > 0.0 {
set_display_value(format!("-{}", temp));
val.set(format!("-{}", temp));
} else {
set_display_value(format!("{}", temp.abs()));
val.set(format!("{}", temp.abs()));
}
},
"±"
@ -89,8 +85,8 @@ fn app(cx: Scope) -> Element {
button {
class: "calculator-key key-percent",
onclick: move |_| {
set_display_value(
format!("{}", calc_val(display_value.clone()) / 100.0)
val.set(
format!("{}", calc_val(val.as_str()) / 100.0)
);
},
"%"
@ -100,7 +96,7 @@ fn app(cx: Scope) -> Element {
button { class: "calculator-key key-0", onclick: move |_| input_digit(0),
"0"
}
button { class: "calculator-key key-dot", onclick: move |_| set_display_value.make_mut().push('.'),
button { class: "calculator-key key-dot", onclick: move |_| val.make_mut().push('.'),
""
}
(1..10).map(|k| rsx!{
@ -114,25 +110,21 @@ fn app(cx: Scope) -> Element {
}
}
div { class: "operator-keys",
button { class: "calculator-key key-divide",
onclick: move |_| input_operator("/"),
button { class: "calculator-key key-divide", onclick: move |_| input_operator("/"),
"÷"
}
button { class: "calculator-key key-multiply",
onclick: move |_| input_operator("*"),
button { class: "calculator-key key-multiply", onclick: move |_| input_operator("*"),
"×"
}
button { class: "calculator-key key-subtract",
onclick: move |_| input_operator("-"),
button { class: "calculator-key key-subtract", onclick: move |_| input_operator("-"),
""
}
button { class: "calculator-key key-add",
onclick: move |_| input_operator("+"),
button { class: "calculator-key key-add", onclick: move |_| input_operator("+"),
"+"
}
button { class: "calculator-key key-equals",
onclick: move |_| {
set_display_value(format!("{}", calc_val(display_value.clone())));
val.set(format!("{}", calc_val(val.as_str())));
},
"="
}
@ -145,7 +137,7 @@ fn app(cx: Scope) -> Element {
))
}
fn calc_val(val: String) -> f64 {
fn calc_val(val: &str) -> f64 {
let mut temp = String::new();
let mut operation = "+".to_string();

View file

@ -21,10 +21,10 @@ pub struct Client {
fn app(cx: Scope) -> Element {
let clients = use_ref(&cx, || vec![] as Vec<Client>);
let (scene, set_scene) = use_state(&cx, || Scene::ClientsList);
let (firstname, set_firstname) = use_state(&cx, String::new);
let (lastname, set_lastname) = use_state(&cx, String::new);
let (description, set_description) = use_state(&cx, String::new);
let scene = use_state(&cx, || Scene::ClientsList);
let firstname = use_state(&cx, String::new);
let lastname = use_state(&cx, String::new);
let description = use_state(&cx, String::new);
cx.render(rsx!(
body {
@ -38,7 +38,7 @@ fn app(cx: Scope) -> Element {
h1 {"Dioxus CRM Example"}
match scene {
match scene.get() {
Scene::ClientsList => rsx!(
div { class: "crm",
h2 { margin_bottom: "10px", "List of clients" }
@ -51,8 +51,8 @@ fn app(cx: Scope) -> Element {
})
)
}
button { class: "pure-button pure-button-primary", onclick: move |_| set_scene(Scene::NewClientForm), "Add New" }
button { class: "pure-button", onclick: move |_| set_scene(Scene::Settings), "Settings" }
button { class: "pure-button pure-button-primary", onclick: move |_| scene.set(Scene::NewClientForm), "Add New" }
button { class: "pure-button", onclick: move |_| scene.set(Scene::Settings), "Settings" }
}
),
Scene::NewClientForm => rsx!(
@ -63,36 +63,36 @@ fn app(cx: Scope) -> Element {
class: "new-client firstname",
placeholder: "First name",
value: "{firstname}",
oninput: move |e| set_firstname(e.value.clone())
oninput: move |e| firstname.set(e.value.clone())
}
input {
class: "new-client lastname",
placeholder: "Last name",
value: "{lastname}",
oninput: move |e| set_lastname(e.value.clone())
oninput: move |e| lastname.set(e.value.clone())
}
textarea {
class: "new-client description",
placeholder: "Description",
value: "{description}",
oninput: move |e| set_description(e.value.clone())
oninput: move |e| description.set(e.value.clone())
}
}
button {
class: "pure-button pure-button-primary",
onclick: move |_| {
clients.write().push(Client {
description: (*description).clone(),
first_name: (*firstname).clone(),
last_name: (*lastname).clone(),
description: (**description).clone(),
first_name: (**firstname).clone(),
last_name: (**lastname).clone(),
});
set_description(String::new());
set_firstname(String::new());
set_lastname(String::new());
description.set(String::new());
firstname.set(String::new());
lastname.set(String::new());
},
"Add New"
}
button { class: "pure-button", onclick: move |_| set_scene(Scene::ClientsList),
button { class: "pure-button", onclick: move |_| scene.set(Scene::ClientsList),
"Go Back"
}
}
@ -108,7 +108,7 @@ fn app(cx: Scope) -> Element {
}
button {
class: "pure-button pure-button-primary",
onclick: move |_| set_scene(Scene::ClientsList),
onclick: move |_| scene.set(Scene::ClientsList),
"Go Back"
}
}

View file

@ -5,13 +5,15 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (disabled, set_disabled) = use_state(&cx, || false);
let disabled = use_state(&cx, || false);
cx.render(rsx! {
div {
button {
onclick: move |_| set_disabled(!disabled),
"click to " [if *disabled {"enable"} else {"disable"} ] " the lower button"
onclick: move |_| disabled.set(!disabled),
"click to "
[if disabled == true {"enable"} else {"disable"}]
" the lower button"
}
button {

View file

@ -16,7 +16,7 @@ struct ListBreeds {
}
fn app(cx: Scope) -> Element {
let (breed, set_breed) = use_state(&cx, || None);
let breed = use_state(&cx, || None);
let breeds = use_future(&cx, (), |_| async move {
reqwest::get("https://dog.ceo/api/breeds/list/all")
@ -32,17 +32,17 @@ fn app(cx: Scope) -> Element {
h1 { "Select a dog breed!" }
div { display: "flex",
ul { flex: "50%",
breeds.message.keys().map(|breed| rsx!(
breeds.message.keys().map(|cur_breed| rsx!(
li {
button {
onclick: move |_| set_breed(Some(breed.clone())),
"{breed}"
onclick: move |_| breed.set(Some(cur_breed.clone())),
"{cur_breed}"
}
}
))
}
div { flex: "50%",
match breed {
match breed.get() {
Some(breed) => rsx!( Breed { breed: breed.clone() } ),
None => rsx!("No Breed selected"),
}

View file

@ -33,7 +33,7 @@ impl Label {
fn app(cx: Scope) -> Element {
let items = use_ref(&cx, Vec::new);
let (selected, set_selected) = use_state(&cx, || None);
let selected = use_state(&cx, || None);
cx.render(rsx! {
div { class: "container",
@ -71,7 +71,7 @@ fn app(cx: Scope) -> Element {
rsx!(tr { class: "{is_in_danger}",
td { class:"col-md-1" }
td { class:"col-md-1", "{item.key}" }
td { class:"col-md-1", onclick: move |_| set_selected(Some(id)),
td { class:"col-md-1", onclick: move |_| selected.set(Some(id)),
a { class: "lbl", item.labels }
}
td { class: "col-md-1",

View file

@ -20,13 +20,13 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (val, set_val) = use_state(&cx, || 0);
let val = use_state(&cx, || 0);
cx.render(rsx! {
div {
h1 { "hello world. Count: {val}" }
button {
onclick: move |_| set_val(val + 1),
onclick: move |_| *val.make_mut() += 1,
"click to increment"
}
}

View file

@ -15,16 +15,16 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (state, set_state) = use_state(&cx, PlayerState::new);
let state = use_state(&cx, PlayerState::new);
cx.render(rsx!(
div {
h1 {"Select an option"}
h3 { "The radio is... " [state.is_playing()] "!" }
button { onclick: move |_| set_state.make_mut().reduce(PlayerAction::Pause),
button { onclick: move |_| state.make_mut().reduce(PlayerAction::Pause),
"Pause"
}
button { onclick: move |_| set_state.make_mut().reduce(PlayerAction::Play),
button { onclick: move |_| state.make_mut().reduce(PlayerAction::Play),
"Play"
}
}

View file

@ -9,13 +9,13 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (count, set_count) = use_state(&cx, || 0);
let count = use_state(&cx, || 0);
cx.render(rsx! {
div {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| set_count(count + 1), "Up high!" }
button { onclick: move |_| set_count(count - 1), "Down low!" }
button { onclick: move |_| *count.make_mut() += 1, "Up high!" }
button { onclick: move |_| *count.make_mut() -= 1, "Down low!" }
}
})
}

View file

@ -12,7 +12,7 @@ fn main() {
}
fn example(cx: Scope) -> Element {
let (items, _set_items) = use_state(&cx, || {
let items = use_state(&cx, || {
vec![Thing {
a: "asd".to_string(),
b: 10,

View file

@ -7,7 +7,7 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (val, set_val) = use_state(&cx, || 5);
let val = use_state(&cx, || 5);
cx.render(rsx! {
div {
@ -21,12 +21,12 @@ fn app(cx: Scope) -> Element {
height: "80%",
width: "80%",
Die {
value: *val,
value: **val,
keep: true,
onclick: move |_| {
use rand::Rng;
let mut rng = rand::thread_rng();
set_val(rng.gen_range(1..6));
val.set(rng.gen_range(1..6));
}
}
}

View file

@ -10,14 +10,14 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (count, set_count) = use_state(&cx, || 0);
let count = use_state(&cx, || 0);
use_future(&cx, (), move |_| {
let set_count = set_count.clone();
let count = count.clone();
async move {
loop {
tokio::time::sleep(Duration::from_millis(1000)).await;
set_count.modify(|f| f + 1);
count.modify(|f| f + 1);
}
}
});
@ -26,7 +26,7 @@ fn app(cx: Scope) -> Element {
div {
h1 { "Current count: {count}" }
button {
onclick: move |_| set_count(0),
onclick: move |_| count.set(0),
"Reset the count"
}
}

View file

@ -7,7 +7,7 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (model, set_model) = use_state(&cx, || String::from("asd"));
let model = use_state(&cx, || String::from("asd"));
println!("{}", model);
@ -17,7 +17,7 @@ fn app(cx: Scope) -> Element {
rows: "10",
cols: "80",
value: "{model}",
oninput: move |e| set_model(e.value.clone()),
oninput: move |e| model.set(e.value.clone()),
}
})
}

View file

@ -19,15 +19,15 @@ pub struct TodoItem {
}
pub fn app(cx: Scope<()>) -> Element {
let (todos, set_todos) = use_state(&cx, im_rc::HashMap::<u32, TodoItem>::default);
let (filter, set_filter) = use_state(&cx, || FilterState::All);
let (draft, set_draft) = use_state(&cx, || "".to_string());
let (todo_id, set_todo_id) = use_state(&cx, || 0);
let todos = use_state(&cx, im_rc::HashMap::<u32, TodoItem>::default);
let filter = use_state(&cx, || FilterState::All);
let draft = use_state(&cx, || "".to_string());
let todo_id = use_state(&cx, || 0);
// Filter the todos based on the filter state
let mut filtered_todos = todos
.iter()
.filter(|(_, item)| match filter {
.filter(|(_, item)| match **filter {
FilterState::All => true,
FilterState::Active => !item.checked,
FilterState::Completed => item.checked,
@ -54,25 +54,25 @@ pub fn app(cx: Scope<()>) -> Element {
placeholder: "What needs to be done?",
value: "{draft}",
autofocus: "true",
oninput: move |evt| set_draft(evt.value.clone()),
oninput: move |evt| draft.set(evt.value.clone()),
onkeydown: move |evt| {
if evt.key == "Enter" && !draft.is_empty() {
set_todos.make_mut().insert(
*todo_id,
todos.make_mut().insert(
**todo_id,
TodoItem {
id: *todo_id,
id: **todo_id,
checked: false,
contents: draft.clone(),
contents: draft.to_string(),
},
);
set_todo_id(todo_id + 1);
set_draft("".to_string());
*todo_id.make_mut() += 1;
draft.set("".to_string());
}
}
}
}
ul { class: "todo-list",
filtered_todos.iter().map(|id| rsx!(todo_entry( key: "{id}", id: *id, set_todos: set_todos )))
filtered_todos.iter().map(|id| rsx!(todo_entry( key: "{id}", id: *id, todos: todos )))
}
(!todos.is_empty()).then(|| rsx!(
footer { class: "footer",
@ -81,14 +81,14 @@ pub fn app(cx: Scope<()>) -> Element {
span {"{item_text} left"}
}
ul { class: "filters",
li { class: "All", a { onclick: move |_| set_filter(FilterState::All), "All" }}
li { class: "Active", a { onclick: move |_| set_filter(FilterState::Active), "Active" }}
li { class: "Completed", a { onclick: move |_| set_filter(FilterState::Completed), "Completed" }}
li { class: "All", a { onclick: move |_| filter.set(FilterState::All), "All" }}
li { class: "Active", a { onclick: move |_| filter.set(FilterState::Active), "Active" }}
li { class: "Completed", a { onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
}
(show_clear_completed).then(|| rsx!(
button {
class: "clear-completed",
onclick: move |_| set_todos.make_mut().retain(|_, todo| !todo.checked),
onclick: move |_| todos.make_mut().retain(|_, todo| !todo.checked),
"Clear completed"
}
))
@ -106,29 +106,29 @@ pub fn app(cx: Scope<()>) -> Element {
#[derive(Props)]
pub struct TodoEntryProps<'a> {
set_todos: &'a UseState<im_rc::HashMap<u32, TodoItem>>,
todos: &'a UseState<im_rc::HashMap<u32, TodoItem>>,
id: u32,
}
pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
let (is_editing, set_is_editing) = use_state(&cx, || false);
let is_editing = use_state(&cx, || false);
let todos = cx.props.set_todos.get();
let todos = cx.props.todos.get();
let todo = &todos[&cx.props.id];
let completed = if todo.checked { "completed" } else { "" };
let editing = if *is_editing { "editing" } else { "" };
let editing = if **is_editing { "editing" } else { "" };
rsx!(cx, li {
class: "{completed} {editing}",
div { class: "view",
input { class: "toggle", r#type: "checkbox", id: "cbg-{todo.id}", checked: "{todo.checked}",
onchange: move |evt| {
cx.props.set_todos.make_mut()[&cx.props.id].checked = evt.value.parse().unwrap();
cx.props.todos.make_mut()[&cx.props.id].checked = evt.value.parse().unwrap();
}
}
label {
r#for: "cbg-{todo.id}",
onclick: move |_| set_is_editing(true),
onclick: move |_| is_editing.set(true),
"{todo.contents}"
}
}
@ -136,12 +136,12 @@ pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
input {
class: "edit",
value: "{todo.contents}",
oninput: move |evt| cx.props.set_todos.make_mut()[&cx.props.id].contents = evt.value.clone(),
oninput: move |evt| cx.props.todos.make_mut()[&cx.props.id].contents = evt.value.clone(),
autofocus: "true",
onfocusout: move |_| set_is_editing(false),
onfocusout: move |_| is_editing.set(false),
onkeydown: move |evt| {
match evt.key.as_str() {
"Enter" | "Escape" | "Tab" => set_is_editing(false),
"Enter" | "Escape" | "Tab" => is_editing.set(false),
_ => {}
}
},

View file

@ -13,9 +13,9 @@ fn app(cx: Scope) -> Element {
// window.set_fullscreen(true);
// window.set_resizable(false);
let (fullscreen, set_fullscreen) = use_state(&cx, || false);
let (always_on_top, set_always_on_top) = use_state(&cx, || false);
let (decorations, set_decorations) = use_state(&cx, || false);
let fullscreen = use_state(&cx, || false);
let always_on_top = use_state(&cx, || false);
let decorations = use_state(&cx, || false);
cx.render(rsx!(
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
@ -39,10 +39,9 @@ fn app(cx: Scope) -> Element {
onmousedown: |evt| evt.cancel_bubble(),
onclick: move |_| {
window.set_fullscreen(!fullscreen);
window.set_resizable(*fullscreen);
set_fullscreen(!fullscreen);
window.set_fullscreen(!**fullscreen);
window.set_resizable(**fullscreen);
fullscreen.modify(|f| !*f);
},
"Fullscreen"
}
@ -65,7 +64,7 @@ fn app(cx: Scope) -> Element {
onmousedown: |evt| evt.cancel_bubble(),
onclick: move |_| {
window.set_always_on_top(!always_on_top);
set_always_on_top(!always_on_top);
always_on_top.set(!always_on_top);
},
"Always On Top"
}
@ -76,7 +75,7 @@ fn app(cx: Scope) -> Element {
onmousedown: |evt| evt.cancel_bubble(),
onclick: move |_| {
window.set_decorations(!decorations);
set_decorations(!decorations);
decorations.set(!decorations);
},
"Set Decorations"
}

View file

@ -9,7 +9,7 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let (contents, set_contents) = use_state(&cx, || {
let contents = use_state(&cx, || {
String::from("<script>alert(\"hello world\")</script>")
});
@ -20,7 +20,7 @@ fn app(cx: Scope) -> Element {
input {
value: "{contents}",
r#type: "text",
oninput: move |e| set_contents(e.value.clone()),
oninput: move |e| contents.set(e.value.clone()),
}
}
})

View file

@ -4,6 +4,7 @@ use dioxus_core::prelude::*;
use std::{
cell::{RefCell, RefMut},
fmt::{Debug, Display},
ops::Not,
rc::Rc,
sync::Arc,
};
@ -18,13 +19,13 @@ use std::{
///
/// ```ignore
/// const Example: Component = |cx| {
/// let (count, set_count) = use_state(&cx, || 0);
/// let count = use_state(&cx, || 0);
///
/// cx.render(rsx! {
/// div {
/// h1 { "Count: {count}" }
/// button { onclick: move |_| set_count(a - 1), "Increment" }
/// button { onclick: move |_| set_count(a + 1), "Decrement" }
/// button { onclick: move |_| *count.modify() += 1, "Increment" }
/// button { onclick: move |_| *count.modify() -= 1, "Decrement" }
/// }
/// ))
/// }
@ -32,7 +33,7 @@ use std::{
pub fn use_state<'a, T: 'static>(
cx: &'a ScopeState,
initial_state_fn: impl FnOnce() -> T,
) -> (&'a T, &'a UseState<T>) {
) -> &'a UseState<T> {
let hook = cx.use_hook(move |_| {
let current_val = Rc::new(initial_state_fn());
let update_callback = cx.schedule_update();
@ -65,7 +66,7 @@ pub fn use_state<'a, T: 'static>(
hook.current_val = hook.slot.borrow().clone();
(hook.current_val.as_ref(), hook)
hook
}
pub struct UseState<T: 'static> {
@ -76,6 +77,11 @@ pub struct UseState<T: 'static> {
}
impl<T: 'static> UseState<T> {
/// Set the state to a new value.
pub fn set(&self, new: T) {
(self.setter)(new);
}
/// Get the current value of the state by cloning its container Rc.
///
/// This is useful when you are dealing with state in async contexts but need
@ -188,7 +194,12 @@ impl<T: 'static> UseState<T> {
/// }
/// ```
#[must_use]
pub fn get(&self) -> &Rc<T> {
pub fn get(&self) -> &T {
&self.current_val
}
#[must_use]
pub fn get_rc(&self) -> &Rc<T> {
&self.current_val
}
@ -260,7 +271,7 @@ impl<T: Clone> UseState<T> {
/// ```
/// let (val, set_val) = use_state(&cx, || 0);
///
/// set_val.with_mut(|v| *v = 1);
/// *set_val.make_mut() += 1;
/// ```
#[must_use]
pub fn make_mut(&self) -> RefMut<T> {
@ -293,10 +304,22 @@ impl<'a, T: 'static + Display> std::fmt::Display for UseState<T> {
}
}
impl<T> PartialEq<UseState<T>> for UseState<T> {
impl<T: PartialEq> PartialEq<T> for UseState<T> {
fn eq(&self, other: &T) -> bool {
self.current_val.as_ref() == other
}
}
// todo: this but for more interesting conrete types
impl PartialEq<bool> for &UseState<bool> {
fn eq(&self, other: &bool) -> bool {
self.current_val.as_ref() == other
}
}
impl<T: PartialEq> PartialEq<UseState<T>> for UseState<T> {
fn eq(&self, other: &UseState<T>) -> bool {
// some level of memoization for UseState
Rc::ptr_eq(&self.slot, &other.slot)
Rc::ptr_eq(&self.current_val, &other.current_val)
}
}
@ -307,10 +330,57 @@ impl<T: Debug> Debug for UseState<T> {
}
impl<'a, T> std::ops::Deref for UseState<T> {
type Target = Rc<dyn Fn(T)>;
type Target = T;
fn deref(&self) -> &Self::Target {
&self.setter
self.current_val.as_ref()
}
}
impl<T: Not + Copy> std::ops::Not for &UseState<T> {
type Output = <T as std::ops::Not>::Output;
fn not(self) -> Self::Output {
self.current_val.not()
}
}
impl<T: Not + Copy> std::ops::Not for UseState<T> {
type Output = <T as std::ops::Not>::Output;
fn not(self) -> Self::Output {
self.current_val.not()
}
}
impl<T: std::ops::Add + Copy> std::ops::Add<T> for &UseState<T> {
type Output = <T as std::ops::Add>::Output;
fn add(self, other: T) -> Self::Output {
*self.current_val.as_ref() + other
}
}
impl<T: std::ops::Sub + Copy> std::ops::Sub<T> for &UseState<T> {
type Output = <T as std::ops::Sub>::Output;
fn sub(self, other: T) -> Self::Output {
*self.current_val.as_ref() - other
}
}
impl<T: std::ops::Div + Copy> std::ops::Div<T> for &UseState<T> {
type Output = <T as std::ops::Div>::Output;
fn div(self, other: T) -> Self::Output {
*self.current_val.as_ref() / other
}
}
impl<T: std::ops::Mul + Copy> std::ops::Mul<T> for &UseState<T> {
type Output = <T as std::ops::Mul>::Output;
fn mul(self, other: T) -> Self::Output {
*self.current_val.as_ref() * other
}
}
@ -318,16 +388,16 @@ impl<'a, T> std::ops::Deref for UseState<T> {
fn api_makes_sense() {
#[allow(unused)]
fn app(cx: Scope) -> Element {
let (val, set_val) = use_state(&cx, || 0);
let val = use_state(&cx, || 0);
set_val(0);
set_val.modify(|v| v + 1);
let real_current = set_val.current();
val.set(0);
val.modify(|v| v + 1);
let real_current = val.current();
match val {
match val.get() {
10 => {
set_val(20);
set_val.modify(|v| v + 1);
val.set(20);
val.modify(|v| v + 1);
}
20 => {}
_ => {
@ -336,9 +406,9 @@ fn api_makes_sense() {
}
cx.spawn({
dioxus_core::to_owned![set_val];
dioxus_core::to_owned![val];
async move {
set_val.modify(|f| f + 1);
val.modify(|f| f + 1);
}
});