diff --git a/examples/calculator.rs b/examples/calculator.rs index 2dbbde02b..be96de93c 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -27,9 +27,9 @@ const App: FC<()> = |cx| { let clear_display = display_value == "0"; let clear_text = if clear_display { "C" } else { "AC" }; - let input_digit = move |num: u8| display_value.get_mut().push_str(num.to_string().as_str()); + let input_digit = move |num: u8| display_value.modify().push_str(num.to_string().as_str()); - let input_dot = move || display_value.get_mut().push_str("."); + let input_dot = move || display_value.modify().push_str("."); let perform_operation = move || { if let Some(op) = operator.as_ref() { @@ -67,7 +67,7 @@ const App: FC<()> = |cx| { let keydownhandler = move |evt: KeyboardEvent| match evt.key_code() { KeyCode::Backspace => { if !display_value.as_str().eq("0") { - display_value.get_mut().pop(); + display_value.modify().pop(); } } KeyCode::_0 => input_digit(0), diff --git a/examples/file_explorer.rs b/examples/file_explorer.rs index bedb3d23d..5d4a89b32 100644 --- a/examples/file_explorer.rs +++ b/examples/file_explorer.rs @@ -25,7 +25,7 @@ static App: FC<()> = |cx| { let file_list = files.path_names.iter().enumerate().map(|(dir_id, path)| { rsx! ( - li { a {"{path}", onclick: move |_| files.get_mut().enter_dir(dir_id), href: "#"} } + li { a {"{path}", onclick: move |_| files.modify().enter_dir(dir_id), href: "#"} } ) }); @@ -33,7 +33,7 @@ static App: FC<()> = |cx| { rsx! { div { code {"{err}"} - button {"x", onclick: move |_| files.get_mut().clear_err() } + button {"x", onclick: move |_| files.modify().clear_err() } } } }); @@ -43,7 +43,7 @@ static App: FC<()> = |cx| { div { h1 {"Files: "} h3 {"Cur dir: {cur}"} - button { "go up", onclick: move |_| files.get_mut().go_up() } + button { "go up", onclick: move |_| files.modify().go_up() } ol { {file_list} } {err_disp} } diff --git a/examples/model.rs b/examples/model.rs index f65355a8a..ac294fd76 100644 --- a/examples/model.rs +++ b/examples/model.rs @@ -42,29 +42,29 @@ static App: FC<()> = |cx| { cx.render(rsx! { div { id: "wrapper" div { class: "app", style { "{STYLE}" } - div { class: "calculator", onkeypress: move |evt| state.get_mut().handle_keydown(evt), + div { class: "calculator", onkeypress: move |evt| state.modify().handle_keydown(evt), div { class: "calculator-display", "{formatted}"} div { class: "calculator-keypad" div { class: "input-keys" div { class: "function-keys" - CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().clear_display(), "{clear_text}" } - CalculatorKey { name: "key-sign", onclick: move |_| state.get_mut().toggle_sign(), "±"} - CalculatorKey { name: "key-percent", onclick: move |_| state.get_mut().toggle_percent(), "%"} + CalculatorKey { name: "key-clear", onclick: move |_| state.modify().clear_display(), "{clear_text}" } + CalculatorKey { name: "key-sign", onclick: move |_| state.modify().toggle_sign(), "±"} + CalculatorKey { name: "key-percent", onclick: move |_| state.modify().toggle_percent(), "%"} } div { class: "digit-keys" - CalculatorKey { name: "key-0", onclick: move |_| state.get_mut().input_digit(0), "0" } - CalculatorKey { name: "key-dot", onclick: move |_| state.get_mut().input_dot(), "●" } + CalculatorKey { name: "key-0", onclick: move |_| state.modify().input_digit(0), "0" } + CalculatorKey { name: "key-dot", onclick: move |_| state.modify().input_dot(), "●" } {(1..10).map(move |k| rsx!{ - CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.get_mut().input_digit(k), "{k}" } + CalculatorKey { key: "{k}", name: "key-{k}", onclick: move |_| state.modify().input_digit(k), "{k}" } })} } } div { class: "operator-keys" - CalculatorKey { name:"key-divide", onclick: move |_| state.get_mut().set_operator(Operator::Div), "÷" } - CalculatorKey { name:"key-multiply", onclick: move |_| state.get_mut().set_operator(Operator::Mul), "×" } - CalculatorKey { name:"key-subtract", onclick: move |_| state.get_mut().set_operator(Operator::Sub), "−" } - CalculatorKey { name:"key-add", onclick: move |_| state.get_mut().set_operator(Operator::Add), "+" } - CalculatorKey { name:"key-equals", onclick: move |_| state.get_mut().perform_operation(), "=" } + CalculatorKey { name:"key-divide", onclick: move |_| state.modify().set_operator(Operator::Div), "÷" } + CalculatorKey { name:"key-multiply", onclick: move |_| state.modify().set_operator(Operator::Mul), "×" } + CalculatorKey { name:"key-subtract", onclick: move |_| state.modify().set_operator(Operator::Sub), "−" } + CalculatorKey { name:"key-add", onclick: move |_| state.modify().set_operator(Operator::Add), "+" } + CalculatorKey { name:"key-equals", onclick: move |_| state.modify().perform_operation(), "=" } } } } diff --git a/examples/reducer.rs b/examples/reducer.rs index 2f93beeee..7a2bf7de2 100644 --- a/examples/reducer.rs +++ b/examples/reducer.rs @@ -22,11 +22,11 @@ pub static App: FC<()> = |cx| { h3 {"The radio is... {is_playing}!"} button { "Pause" - onclick: move |_| state.get_mut().reduce(PlayerAction::Pause) + onclick: move |_| state.modify().reduce(PlayerAction::Pause) } button { "Play" - onclick: move |_| state.get_mut().reduce(PlayerAction::Play) + onclick: move |_| state.modify().reduce(PlayerAction::Play) } } }) diff --git a/examples/slideshow.rs b/examples/slideshow.rs index 7aa09b7af..97391c033 100644 --- a/examples/slideshow.rs +++ b/examples/slideshow.rs @@ -34,9 +34,9 @@ static App: FC<()> = |cx| { div { div { h1 {"my awesome slideshow"} } div { - button {"<-", onclick: move |_| slides.get_mut().go_forward()} + button {"<-", onclick: move |_| slides.modify().go_forward()} h3 { "{slides.slide_id}" } - button {"->" onclick: move |_| slides.get_mut().go_backward()} + button {"->" onclick: move |_| slides.modify().go_backward()} } } {slide} diff --git a/examples/webview.rs b/examples/webview.rs index 8759fc733..8178684de 100644 --- a/examples/webview.rs +++ b/examples/webview.rs @@ -25,8 +25,8 @@ static App: FC<()> = |cx| { cx.render(rsx! { div { h1 {"{state}"} - CalculatorKey { name: "key-clear", onclick: move |_| state.get_mut().push_str("hello"), "{clear_text}" } - CalculatorKey { name: "key-sign", onclick: move |_| { state.get_mut().pop(); }, "±"} + CalculatorKey { name: "key-clear", onclick: move |_| state.modify().push_str("hello"), "{clear_text}" } + CalculatorKey { name: "key-sign", onclick: move |_| { state.modify().pop(); }, "±"} } }) }; diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 0d9c2442d..7cc51dab4 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -188,6 +188,8 @@ pub(crate) fn event_meta(event: &UserEvent) -> (bool, EventPriority) { } } +pub use on::KeyCode; + pub mod on { //! This module defines the synthetic events that all Dioxus apps enable. No matter the platform, every dioxus renderer //! will implement the same events and same behavior (bubbling, cancelation, etc). diff --git a/packages/hooks/src/lib.rs b/packages/hooks/src/lib.rs index 97c759b33..6a0722d95 100644 --- a/packages/hooks/src/lib.rs +++ b/packages/hooks/src/lib.rs @@ -1,2 +1,5 @@ mod usestate; -pub use usestate::use_state; +pub use usestate::{use_state, AsyncUseState, UseState}; + +mod useref; +pub use useref::*; diff --git a/packages/hooks/src/useref.rs b/packages/hooks/src/useref.rs index e69de29bb..4254c2e52 100644 --- a/packages/hooks/src/useref.rs +++ b/packages/hooks/src/useref.rs @@ -0,0 +1,38 @@ +use std::cell::{Ref, RefCell, RefMut}; + +use dioxus_core::Context; + +pub struct UseRef<'a, T> { + inner: &'a RefCell, +} + +impl<'a, T> UseRef<'a, T> { + pub fn read(&self) -> Ref<'_, T> { + self.inner.borrow() + } + + pub fn read_write(&self) -> (Ref<'_, T>, &Self) { + (self.read(), self) + } + + /// Calling "write" will force the component to re-render + pub fn write(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } + + /// Allows the ability to write the value without forcing a re-render + pub fn write_silent(&self) -> RefMut<'_, T> { + self.inner.borrow_mut() + } +} + +impl Clone for UseRef<'_, T> { + fn clone(&self) -> Self { + Self { inner: self.inner } + } +} +impl Copy for UseRef<'_, T> {} + +pub fn use_ref(cx: Context

, f: impl FnOnce() -> T) -> UseRef { + cx.use_hook(|_| RefCell::new(f()), |f| UseRef { inner: f }, |_| {}) +} diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs index f0d3abc43..ea0040be9 100644 --- a/packages/hooks/src/usestate.rs +++ b/packages/hooks/src/usestate.rs @@ -82,6 +82,7 @@ struct UseStateInner { pub struct UseState<'a, T: 'static> { inner: &'a UseStateInner, } + impl Copy for UseState<'_, T> {} impl<'a, T> Clone for UseState<'a, T> where @@ -115,6 +116,11 @@ impl<'a, T: 'static> UseState<'a, T> { self.inner.wip.borrow() } + /// Get the current status of the work-in-progress data + pub fn get_wip_mut(&self) -> RefMut> { + self.inner.wip.borrow_mut() + } + pub fn classic(self) -> (&'a T, &'a Rc) { todo!() } @@ -136,7 +142,12 @@ impl<'a, T: 'static> UseState<'a, T> { } impl<'a, T: 'static + ToOwned> UseState<'a, T> { - pub fn get_mut(self) -> RefMut<'a, T> { + /// Gain mutable access to the new value. This method is only available when the value is a `ToOwned` type. + /// + /// Mutable access is derived by calling "ToOwned" (IE cloning) on the current value. + /// + /// To get a reference to the current value, use `.get()` + pub fn modify(self) -> RefMut<'a, T> { // make sure we get processed self.needs_update();