From 6f6a36d3957f6088e69dca7408c5e8d5d70bf95a Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 18 Dec 2023 18:20:44 -0800 Subject: [PATCH 1/3] Remove async variants Rplace with a couple helper functions --- crates/yewdux-macros/src/lib.rs | 11 - crates/yewdux/Cargo.toml | 3 - crates/yewdux/src/context.rs | 44 +-- crates/yewdux/src/dispatch.rs | 519 ++--------------------------- crates/yewdux/src/lib.rs | 9 - crates/yewdux/src/store.rs | 50 +-- examples/async_reducer/Cargo.toml | 13 - examples/async_reducer/index.html | 4 - examples/async_reducer/src/main.rs | 96 ------ examples/future/Cargo.toml | 3 + examples/future/src/main.rs | 59 +++- 11 files changed, 82 insertions(+), 729 deletions(-) delete mode 100644 examples/async_reducer/Cargo.toml delete mode 100644 examples/async_reducer/index.html delete mode 100644 examples/async_reducer/src/main.rs diff --git a/crates/yewdux-macros/src/lib.rs b/crates/yewdux-macros/src/lib.rs index 3106126..eebfb49 100644 --- a/crates/yewdux-macros/src/lib.rs +++ b/crates/yewdux-macros/src/lib.rs @@ -1,6 +1,5 @@ use proc_macro::TokenStream; use proc_macro_error::proc_macro_error; -use quote::quote; use syn::{parse_macro_input, DeriveInput}; mod store; @@ -11,13 +10,3 @@ pub fn store(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); store::derive(input).into() } - -#[proc_macro_attribute] -pub fn async_reducer(_attr: TokenStream, item: TokenStream) -> TokenStream { - let item = proc_macro2::TokenStream::from(item); - quote! { - #[::yewdux::async_trait(?Send)] - #item - } - .into() -} diff --git a/crates/yewdux/Cargo.toml b/crates/yewdux/Cargo.toml index eb145cb..cafa3a8 100644 --- a/crates/yewdux/Cargo.toml +++ b/crates/yewdux/Cargo.toml @@ -19,7 +19,6 @@ doctests = [] [dependencies] anymap = "1.0.0-beta.2" -async-trait = "0.1.58" log = "0.4.16" serde = { version = "1.0.114", features = ["rc"] } serde_json = "1.0.64" @@ -32,6 +31,4 @@ yewdux-macros = { path = "../yewdux-macros" } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" -[dev-dependencies] -async-std = { version = "1.11", features = ["attributes"] } diff --git a/crates/yewdux/src/context.rs b/crates/yewdux/src/context.rs index f36f04b..7c07cb0 100644 --- a/crates/yewdux/src/context.rs +++ b/crates/yewdux/src/context.rs @@ -1,12 +1,10 @@ use std::rc::Rc; -#[cfg(feature = "future")] -use std::{future::Future, pin::Pin}; use anymap::AnyMap; use crate::{ mrc::Mrc, - store::{AsyncReducer, Reducer, Store}, + store::{Reducer, Store}, subscriber::{Callable, SubscriberId, Subscribers}, }; @@ -33,18 +31,6 @@ impl Entry { // Return whether or not subscribers should be notified. self.store.borrow().should_notify(&old) } - - /// Apply a future reduction to state, returning if it should notify subscribers or not. - #[cfg(feature = "future")] - pub(crate) async fn reduce_future>(&self, reducer: R) -> bool { - let old = Rc::clone(&self.store.borrow()); - // Apply the reducer. - let new = reducer.apply(Rc::clone(&old)).await; - // Update the new state. - *self.store.borrow_mut() = new; - // Return whether or not subscribers should be notified. - self.store.borrow().should_notify(&old) - } } /// Execution context for a dispatch @@ -127,21 +113,6 @@ impl Context { } } - #[cfg(feature = "future")] - pub async fn reduce_future(&self, r: R) - where - S: Store, - R: AsyncReducer, - { - let entry = self.get_or_init::(); - let should_notify = entry.reduce_future(r).await; - - if should_notify { - let state = Rc::clone(&entry.store.borrow()); - self.notify_subscribers(state) - } - } - pub fn reduce_mut(&self, f: F) { self.reduce(|mut state| { f(Rc::make_mut(&mut state)); @@ -149,19 +120,6 @@ impl Context { }); } - #[cfg(feature = "future")] - pub async fn reduce_mut_future(&self, f: F) - where - S: Store + Clone, - F: FnOnce(&mut S) -> Pin + '_>>, - { - self.reduce_future(|mut state| async move { - f(Rc::make_mut(&mut state)).await; - state - }) - .await; - } - /// Set state to given value. pub fn set(&self, value: S) { self.reduce(move |_| value.into()); diff --git a/crates/yewdux/src/dispatch.rs b/crates/yewdux/src/dispatch.rs index 7467fc4..fa86cb0 100644 --- a/crates/yewdux/src/dispatch.rs +++ b/crates/yewdux/src/dispatch.rs @@ -17,15 +17,13 @@ //! ``` //! -use std::rc::Rc; -#[cfg(feature = "future")] -use std::{future::Future, pin::Pin}; +use std::{future::Future, rc::Rc}; use yew::Callback; use crate::{ context::Context, - store::{AsyncReducer, Reducer, Store}, + store::{Reducer, Store}, subscriber::{Callable, SubscriberId}, }; @@ -72,6 +70,37 @@ impl Dispatch { &self.cx } + #[cfg(feature = "future")] + pub fn spawn_future(&self, f: F) + where + F: FnOnce(Self) -> FU, + FU: Future + 'static, + { + yew::platform::spawn_local(f(self.clone())); + } + + #[cfg(feature = "future")] + pub fn future_callback(&self, f: F) -> Callback + where + F: Fn(Self) -> FU + 'static, + FU: Future + 'static, + { + let dispatch = self.clone(); + let f = Rc::new(f); + Callback::from(move |_| dispatch.spawn_future(|dispatch| f(dispatch))) + } + + #[cfg(feature = "future")] + pub fn future_callback_with(&self, f: F) -> Callback + where + F: Fn(Self, E) -> FU + 'static, + FU: Future + 'static, + { + let dispatch = self.clone(); + let f = Rc::new(f); + Callback::from(move |e| dispatch.spawn_future(|dispatch| f(dispatch, e))) + } + /// Create a dispatch that subscribes to changes in state. Latest state is sent immediately, /// and on every subsequent change. Automatically unsubscribes when this dispatch is dropped. /// ``` @@ -182,44 +211,6 @@ impl Dispatch { self.cx.reduce(reducer); } - /// Apply an [`AsyncReducer`](crate::store::AsyncReducer) immediately. - /// - /// ``` - /// # use std::rc::Rc; - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// #[derive(Default, Clone, PartialEq, Eq, Store)] - /// struct State { - /// count: u32, - /// } - /// - /// struct AddOne; - /// #[async_reducer] - /// impl AsyncReducer for AddOne { - /// async fn apply(self, state: Rc) -> Rc { - /// // you can do async things here! - /// let incr = get_incr().await; - /// State { - /// count: state.count + incr, - /// } - /// .into() - /// } - /// } - /// - /// # async fn do_thing() { - /// let dispatch = Dispatch::::global(); - /// dispatch.apply_future(AddOne).await; - /// # ; - /// # } - /// ``` - #[cfg(feature = "future")] - pub async fn apply_future>(&self, reducer: R) { - self.cx.reduce_future(reducer).await; - } - /// Create a callback that applies a [`Reducer`](crate::store::Reducer). /// /// ``` @@ -262,58 +253,6 @@ impl Dispatch { }) } - /// Create a callback for applying an [`AsyncReducer`](crate::store::AsyncReducer). - /// - /// ``` - /// # use std::rc::Rc; - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// #[derive(Default, Clone, PartialEq, Eq, Store)] - /// struct State { - /// count: u32, - /// } - /// - /// struct AddOne; - /// #[async_reducer] - /// impl AsyncReducer for AddOne { - /// async fn apply(self, state: Rc) -> Rc { - /// // you can do async things here! - /// let incr = get_incr().await; - /// State { - /// count: state.count + incr, - /// } - /// .into() - /// } - /// } - /// - /// # fn main() { - /// let dispatch = Dispatch::::global(); - /// let onclick = dispatch.apply_future_callback(|_| AddOne); - /// html! { - /// - /// } - /// # ; - /// # } - /// ``` - #[cfg(feature = "future")] - pub fn apply_future_callback(&self, f: F) -> Callback - where - M: AsyncReducer + 'static, - F: Fn(E) -> M + 'static, - { - let context = self.cx.clone(); - Callback::from(move |e| { - let msg = f(e); - let context = context.clone(); - yew::platform::spawn_local(async move { - context.reduce_future(msg).await; - }) - }) - } - /// Set state to given value immediately. /// /// ``` @@ -386,41 +325,6 @@ impl Dispatch { self.cx.reduce(f); } - /// Change state immediately, in an async context. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # async fn do_thing() { - /// let dispatch = Dispatch::::global(); - /// dispatch - /// .reduce_future(|state| async move { - /// let incr = get_incr().await; - /// State { - /// count: state.count + incr, - /// } - /// .into() - /// }) - /// .await; - /// - /// # } - /// ``` - #[cfg(feature = "future")] - pub async fn reduce_future(&self, f: FUN) - where - FUT: Future>, - FUN: FnOnce(Rc) -> FUT, - { - self.cx.reduce_future(f).await; - } - /// Create a callback that changes state. /// /// ``` @@ -450,51 +354,6 @@ impl Dispatch { }) } - /// Create a callback to reduce state asynchronously. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # fn main() { - /// let dispatch = Dispatch::::global(); - /// let onclick = dispatch.reduce_future_callback(|state| async move { - /// let incr = get_incr().await; - /// State { - /// count: state.count + incr, - /// } - /// .into() - /// }); - /// html! { - /// - /// } - /// # ; - /// # } - /// ``` - #[cfg(feature = "future")] - pub fn reduce_future_callback(&self, f: FUN) -> Callback - where - FUT: Future>, - FUN: Fn(Rc) -> FUT + 'static, - E: 'static, - { - let f = Rc::new(f); - let context = self.cx.clone(); - Callback::from(move |_| { - let f = f.clone(); - let context = context.clone(); - yew::platform::spawn_local(async move { - context.reduce_future(f.as_ref()).await; - }) - }) - } - /// Similar to [Self::reduce_callback] but also provides the fired event. /// /// ``` @@ -530,53 +389,6 @@ impl Dispatch { }) } - /// Create a callback to reduce state asynchronously, with the fired event. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # fn main() { - /// let dispatch = Dispatch::::global(); - /// let onchange = dispatch.reduce_future_callback_with(|state, event: Event| async move { - /// let value = event.target_unchecked_into::().value(); - /// let incr = get_incr().await; - /// let count = value.parse::().unwrap() * incr; - /// State { - /// count: state.count + count, - /// } - /// .into() - /// }); - /// html! { - /// - /// } - /// # ; - /// # } - /// ``` - #[cfg(feature = "future")] - pub fn reduce_future_callback_with(&self, f: FUN) -> Callback - where - FUT: Future>, - FUN: Fn(Rc, E) -> FUT + 'static, - E: 'static, - { - let f = Rc::new(f); - let context = self.cx.clone(); - Callback::from(move |e: E| { - let f = f.clone(); - let context = context.clone(); - yew::platform::spawn_local(async move { - context.reduce_future(move |s| f(s, e)).await; - }) - }) - } - /// Mutate state with given function. /// /// ``` @@ -605,39 +417,6 @@ impl Dispatch { result.expect("result not initialized") } - /// Mutate state with given function, in an async context. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # async fn do_thing() { - /// let dispatch = Dispatch::::global(); - /// dispatch - /// .reduce_mut_future(|state| { - /// Box::pin(async move { - /// let incr = get_incr().await; - /// state.count += incr; - /// }) - /// }) - /// .await; - /// # } - /// ``` - #[cfg(feature = "future")] - pub async fn reduce_mut_future(&self, f: F) - where - S: Clone, - F: FnOnce(&mut S) -> Pin + '_>>, - { - self.cx.reduce_mut_future(f).await; - } - /// Like [Self::reduce_mut] but from a callback. /// /// ``` @@ -670,49 +449,6 @@ impl Dispatch { }) } - /// Create a callback to asynchronously mutate state. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # fn main() { - /// let dispatch = Dispatch::::global(); - /// let onclick = dispatch.reduce_mut_future_callback(|state| Box::pin(async move { - /// let incr = get_incr().await; - /// state.count += incr; - /// })); - /// html! { - /// - /// } - /// # ; - /// # } - /// ``` - /// - #[cfg(feature = "future")] - pub fn reduce_mut_future_callback(&self, f: F) -> Callback - where - S: Clone, - F: Fn(&mut S) -> Pin + '_>> + 'static, - E: 'static, - { - let f = Rc::new(f); - let context = self.cx.clone(); - Callback::from(move |_| { - let f = f.clone(); - let context = context.clone(); - yew::platform::spawn_local(async move { - context.reduce_mut_future(f.as_ref()).await; - }) - }) - } - /// Similar to [Self::reduce_mut_callback] but also provides the fired event. /// /// ``` @@ -747,55 +483,6 @@ impl Dispatch { }); }) } - - /// Create a callback to asynchronously mutate state with given function, provided the fired - /// event. - /// - /// ``` - /// # use yew::prelude::*; - /// # use yewdux::prelude::*; - /// # #[derive(Default, Clone, PartialEq, Eq, Store)] - /// # struct State { - /// # count: u32, - /// # } - /// # async fn get_incr() -> u32 { - /// # 1 - /// # } - /// # #[hook] - /// # fn use_foo() { - /// let dispatch = use_dispatch::(); - /// let onchange = dispatch.reduce_mut_future_callback_with(|state, event: Event| { - /// Box::pin(async move { - /// let value = event - /// .target_unchecked_into::() - /// .value(); - /// let incr = get_incr().await; - /// state.count = value.parse::().unwrap() * incr; - /// }) - /// }); - /// html! { - /// - /// } - /// # ; - /// # } - /// ``` - #[cfg(feature = "future")] - pub fn reduce_mut_future_callback_with(&self, f: F) -> Callback - where - S: Clone, - F: Fn(&mut S, E) -> Pin + '_>> + 'static, - E: 'static, - { - let f = Rc::new(f); - let context = self.cx.clone(); - Callback::from(move |e: E| { - let f = f.clone(); - let context = context.clone(); - yew::platform::spawn_local(async move { - context.reduce_mut_future(move |s| f(s, e)).await; - }) - }) - } } impl Clone for Dispatch { @@ -878,40 +565,6 @@ mod tests { assert!(old != new); } - #[cfg(feature = "future")] - #[async_std::test] - async fn reduce_future_changes_value() { - let cx = Context::new(); - let dispatch = Dispatch::::new(&cx); - let old = dispatch.get(); - - dispatch - .reduce_future(|state| async move { TestState(state.0 + 1).into() }) - .await; - - let new = dispatch.get(); - - assert!(old != new); - } - - #[cfg(feature = "future")] - #[async_std::test] - async fn reduce_future_does_not_clash() { - use std::time::Duration; - - let cx = Context::new(); - let dispatch = Dispatch::::new(&cx); - - dispatch - .reduce_future(|state| async move { - async_std::task::sleep(Duration::from_millis(100)).await; - state - }) - .await; - - dispatch.reduce(|s| s); - } - #[test] fn reduce_mut_changes_value() { let dispatch = Dispatch::::new(&Context::new()); @@ -924,21 +577,6 @@ mod tests { assert!(old != new); } - #[cfg(feature = "future")] - #[async_std::test] - async fn reduce_mut_future_changes_value() { - let dispatch = Dispatch::::new(&Context::new()); - let old = dispatch.get(); - - dispatch - .reduce_mut_future(|state| Box::pin(async move { *state = TestState(1) })) - .await; - - let new = dispatch.get(); - - assert!(old != new); - } - #[test] fn reduce_does_not_require_static() { let val = "1".to_string(); @@ -1008,19 +646,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_mut_future_works() { - let dispatch = Dispatch::::new(&Context::new()); - let old = dispatch.get(); - - dispatch - .reduce_mut_future(|state| Box::pin(async move { state.0 += 1 })) - .await; - - assert!(dispatch.get() != old) - } - #[test] fn dispatch_reduce_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1031,19 +656,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_future_works() { - let dispatch = Dispatch::::new(&Context::new()); - let old = dispatch.get(); - - dispatch - .reduce_future(|state| async move { TestState(state.0 + 1).into() }) - .await; - - assert!(dispatch.get() != old) - } - #[test] fn dispatch_reduce_callback_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1055,16 +667,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_future_callback_compiles() { - let dispatch = Dispatch::::new(&Context::new()); - - let _ = dispatch.reduce_future_callback::<_, _, ()>(|state| async move { - TestState(state.0 + 1).into() - }); - } - #[test] fn dispatch_reduce_mut_callback_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1076,28 +678,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_mut_future_callback_compiles() { - let dispatch = Dispatch::::new(&Context::new()); - - let _ = dispatch.reduce_mut_future_callback::<_, _, ()>(|state| { - Box::pin(async move { - state.0 += 1; - }) - }); - } - - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_future_callback_with_compiles() { - let dispatch = Dispatch::::new(&Context::new()); - - let _ = dispatch.reduce_future_callback_with(|state, e: u32| async move { - TestState(state.0 + e).into() - }); - } - #[test] fn dispatch_reduce_callback_with_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1120,18 +700,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn dispatch_reduce_mut_future_callback_with_compiles() { - let dispatch = Dispatch::::new(&Context::new()); - - let _ = dispatch.reduce_mut_future_callback_with::<_, _, u32>(|state, e| { - Box::pin(async move { - state.0 += e; - }) - }); - } - #[test] fn dispatch_apply_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1142,19 +710,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn apply_future_changes_value() { - let dispatch = Dispatch::::new(&Context::new()); - let old = dispatch.get(); - - dispatch.apply_future(Msg).await; - - let new = dispatch.get(); - - assert!(old != new); - } - #[test] fn dispatch_apply_callback_works() { let dispatch = Dispatch::::new(&Context::new()); @@ -1166,14 +721,6 @@ mod tests { assert!(dispatch.get() != old) } - #[cfg(feature = "future")] - #[async_std::test] - async fn apply_future_callback_compiles() { - let dispatch = Dispatch::::new(&Context::new()); - - dispatch.apply_future_callback(|_: ()| Msg); - } - #[test] fn subscriber_is_notified() { let cx = Context::new(); diff --git a/crates/yewdux/src/lib.rs b/crates/yewdux/src/lib.rs index c4427aa..885068b 100644 --- a/crates/yewdux/src/lib.rs +++ b/crates/yewdux/src/lib.rs @@ -45,10 +45,6 @@ mod subscriber; #[doc(hidden)] pub use log; -#[cfg(feature = "future")] -#[doc(hidden)] -pub use async_trait::async_trait; - // Allow shorthand, like `yewdux::Dispatch` pub use context::Context; pub use prelude::*; @@ -66,9 +62,4 @@ pub mod prelude { listener::{init_listener, Listener}, store::{Reducer, Store}, }; - - #[cfg(feature = "future")] - pub use crate::store::AsyncReducer; - #[cfg(feature = "future")] - pub use yewdux_macros::async_reducer; } diff --git a/crates/yewdux/src/store.rs b/crates/yewdux/src/store.rs index e04bccc..2223e4b 100644 --- a/crates/yewdux/src/store.rs +++ b/crates/yewdux/src/store.rs @@ -1,7 +1,5 @@ //! Unique state shared application-wide -use std::{future::Future, rc::Rc}; - -use async_trait::async_trait; +use std::rc::Rc; pub use yewdux_macros::Store; @@ -71,49 +69,3 @@ where self(state) } } - -/// A type that can change state asynchronously. -/// -/// # Example -/// -/// ``` -/// use std::rc::Rc; -/// -/// use yewdux::prelude::*; -/// -/// #[derive(Default, Clone, PartialEq, Eq, Store)] -/// struct State { -/// count: u32, -/// } -/// -/// struct MyReducer; -/// -/// #[async_reducer] -/// impl AsyncReducer for MyReducer { -/// /// Mutate state. -/// async fn apply(self, state: Rc) -> Rc { -/// // do async things -/// state -/// } -/// } -/// ``` -/// -/// **IMPORTANT**: note the extra `?Send` for the async trait definition. This is required for -/// `AsyncReducer`. -#[async_trait(?Send)] -pub trait AsyncReducer { - /// Mutate state. - async fn apply(self, state: Rc) -> Rc; -} - -#[async_trait(?Send)] -impl AsyncReducer for F -where - S: 'static, - F: FnOnce(Rc) -> FU, - FU: Future>, -{ - async fn apply(self, state: Rc) -> Rc { - self(state).await - } -} diff --git a/examples/async_reducer/Cargo.toml b/examples/async_reducer/Cargo.toml deleted file mode 100644 index b393b3a..0000000 --- a/examples/async_reducer/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "async-reducer" -version = "0.1.0" -authors = ["Noah "] -edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -yew = { git = "https://github.com/yewstack/yew.git", features = ["csr"] } -yewdux = { path = "../../crates/yewdux" } -serde = "1.0" -gloo-net = "0.4" -web-sys = "0.3" diff --git a/examples/async_reducer/index.html b/examples/async_reducer/index.html deleted file mode 100644 index d25b3f3..0000000 --- a/examples/async_reducer/index.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/examples/async_reducer/src/main.rs b/examples/async_reducer/src/main.rs deleted file mode 100644 index 6291073..0000000 --- a/examples/async_reducer/src/main.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::rc::Rc; - -use gloo_net::http::Request; -use serde::{Deserialize, Serialize}; -use web_sys::HtmlInputElement; -use yew::prelude::*; -use yewdux::prelude::*; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Cat { - url: String, -} - -async fn fetch_cats(limit: u32) -> Result, ()> { - let res = Request::get(&format!( - "https://api.thecatapi.com/v1/images/search?limit={}", - limit - )) - .send() - .await - .map_err(|_| ())? - .json::>() - .await - .map_err(|_| ())? - .into_iter() - .collect::>(); - - Ok(res) -} - -#[derive(Default, Clone, PartialEq, Eq, Store)] -struct Cats { - inner: Vec, -} - -enum FetchCats { - Limit(u32), - Single, -} - -#[async_reducer] -impl AsyncReducer for FetchCats { - async fn apply(self, mut cats: Rc) -> Rc { - let limit = match self { - FetchCats::Limit(limit) => limit, - FetchCats::Single => 1, - }; - - if let Ok(val) = fetch_cats(limit).await { - let state = Rc::make_mut(&mut cats); - state.inner.extend(val); - } - - cats - } -} - -#[function_component] -fn App() -> Html { - let (state, dispatch) = use_store::(); - let fetch_unlimited = dispatch.apply_future_callback(|_| FetchCats::Single); - let fetch_limited = dispatch.apply_future_callback(|e: Event| { - let value = e - .target_unchecked_into::() - .value() - .parse() - .unwrap_or_default(); - - FetchCats::Limit(value) - }); - - let cats = state - .inner - .iter() - .map(|Cat { url }| { - html! { - - } - }) - .collect::(); - - html! { - <> - - -
- { cats } -
- - } -} - -fn main() { - yew::Renderer::::new().render(); -} diff --git a/examples/future/Cargo.toml b/examples/future/Cargo.toml index a048f9d..2d28bc7 100644 --- a/examples/future/Cargo.toml +++ b/examples/future/Cargo.toml @@ -9,3 +9,6 @@ edition = "2018" wasm-bindgen-futures = "0.4.30" yew = { git = "https://github.com/yewstack/yew.git", features = ["csr"] } yewdux = { path = "../../crates/yewdux" } +serde = "1.0" +gloo-net = "0.4" +web-sys = "0.3" diff --git a/examples/future/src/main.rs b/examples/future/src/main.rs index fd561bb..8ad57ab 100644 --- a/examples/future/src/main.rs +++ b/examples/future/src/main.rs @@ -1,32 +1,61 @@ +use gloo_net::http::Request; +use serde::{Deserialize, Serialize}; +use web_sys::HtmlInputElement; use yew::prelude::*; use yewdux::prelude::*; -#[derive(Default, Clone, PartialEq, Eq, Store)] -struct State { - count: u32, +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Cat { + url: String, +} + +async fn fetch_cats(limit: u32) -> Result { + let cats = Request::get(&format!( + "https://api.thecatapi.com/v1/images/search?limit={}", + limit + )) + .send() + .await + .map_err(|_| ())? + .json::>() + .await + .map_err(|_| ())? + .into_iter() + .collect::>(); + + Ok(Cats(cats)) } +#[derive(Default, Clone, PartialEq, Eq, Store)] +struct Cats(Vec); + #[function_component] fn App() -> Html { - let (state, dispatch) = use_store::(); + let (state, dispatch) = use_store::(); - let incr = dispatch.reduce_future_callback(|state| async move { - State { - count: state.count + 1, + let fetch_single = dispatch.future_callback(|dispatch| async move { + let result = fetch_cats(5).await; + if let Ok(cats) = result { + dispatch.set(cats); } - .into() }); - let incr_mut = dispatch.reduce_mut_future_callback(|state| { - Box::pin(async move { - state.count += 1; + + let cats = state + .0 + .iter() + .map(|Cat { url }| { + html! { + + } }) - }); + .collect::(); html! { <> -

{ state.count }

- - + +
+ { cats } +
} } From 1a42224eb57db05d373af5f2d79d6b228026f69d Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 18 Dec 2023 18:24:06 -0800 Subject: [PATCH 2/3] Remove unecessary allocation --- crates/yewdux/src/dispatch.rs | 4 +--- examples/future/src/main.rs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/yewdux/src/dispatch.rs b/crates/yewdux/src/dispatch.rs index fa86cb0..c50dfeb 100644 --- a/crates/yewdux/src/dispatch.rs +++ b/crates/yewdux/src/dispatch.rs @@ -86,8 +86,7 @@ impl Dispatch { FU: Future + 'static, { let dispatch = self.clone(); - let f = Rc::new(f); - Callback::from(move |_| dispatch.spawn_future(|dispatch| f(dispatch))) + Callback::from(move |_| dispatch.spawn_future(&f)) } #[cfg(feature = "future")] @@ -97,7 +96,6 @@ impl Dispatch { FU: Future + 'static, { let dispatch = self.clone(); - let f = Rc::new(f); Callback::from(move |e| dispatch.spawn_future(|dispatch| f(dispatch, e))) } diff --git a/examples/future/src/main.rs b/examples/future/src/main.rs index 8ad57ab..dd902a7 100644 --- a/examples/future/src/main.rs +++ b/examples/future/src/main.rs @@ -1,6 +1,5 @@ use gloo_net::http::Request; use serde::{Deserialize, Serialize}; -use web_sys::HtmlInputElement; use yew::prelude::*; use yewdux::prelude::*; From 639d522a67a3b69f0b45648815a52217a8bf97ec Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 18 Dec 2023 18:44:25 -0800 Subject: [PATCH 3/3] Add some docs --- crates/yewdux/src/dispatch.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/crates/yewdux/src/dispatch.rs b/crates/yewdux/src/dispatch.rs index c50dfeb..7546d0d 100644 --- a/crates/yewdux/src/dispatch.rs +++ b/crates/yewdux/src/dispatch.rs @@ -70,6 +70,7 @@ impl Dispatch { &self.cx } + /// Spawn a future with access to this dispatch. #[cfg(feature = "future")] pub fn spawn_future(&self, f: F) where @@ -79,6 +80,7 @@ impl Dispatch { yew::platform::spawn_local(f(self.clone())); } + /// Create a callback that will spawn a future with access to this dispatch. #[cfg(feature = "future")] pub fn future_callback(&self, f: F) -> Callback where @@ -89,6 +91,8 @@ impl Dispatch { Callback::from(move |_| dispatch.spawn_future(&f)) } + /// Create a callback that will spawn a future with access to this dispatch and the emitted + /// event. #[cfg(feature = "future")] pub fn future_callback_with(&self, f: F) -> Callback where @@ -538,13 +542,6 @@ mod tests { } } - #[async_trait::async_trait(?Send)] - impl AsyncReducer for Msg { - async fn apply(self, state: Rc) -> Rc { - TestState(state.0 + 1).into() - } - } - #[test] fn apply_no_clone() { Dispatch::new(&Context::new()).reduce(|_| TestStateNoClone(1).into());