@@ -475,7 +475,8 @@ impl<T> Resource<T> {
475475 /// let guard1 = resource1.read_async().await;
476476 /// drop(guard1);
477477 /// let guard2 = resource2.read_async().await;
478- /// // Value exists
478+ /// // Value exists if used inside another `use_resource`,
479+ /// // since otherwise the resource would have restarted
479480 /// let guard1 = resource1.read().as_ref().unwrap();
480481 /// ```
481482 ///
@@ -521,6 +522,111 @@ impl<T> Resource<T> {
521522 }
522523 read. map ( |e| std:: cell:: Ref :: map ( e, |option| option. as_ref ( ) . unwrap ( ) ) )
523524 }
525+
526+ /// Asynchronously wait for the resource to be ready and return a clone of its value.
527+ ///
528+ /// The primary advantage of `cloned_async` is that it avoids the complex
529+ /// borrowing rules of `read_async` by immediately cloning the value, allowing
530+ /// it to be used freely across further `.await` points.
531+ ///
532+ /// **This method requires `T` to implement `Clone`.**
533+ ///
534+ /// ## Example
535+ ///
536+ /// ```rust,no_run
537+ /// # use dioxus::prelude::*;
538+ /// #[derive(Clone, Debug)]
539+ /// struct User { id: u32, name: String }
540+ ///
541+ /// fn App() -> Element {
542+ /// let user_id = use_signal(|| 42);
543+ /// let user_resource = use_resource(move || async move {
544+ /// // Some expensive fetch that returns a User
545+ /// fetch_user(*user_id.read()).await
546+ /// });
547+ ///
548+ /// let cloned_user = use_resource(move || async move {
549+ /// // Wait for user_resource, clone the User struct, and then continue
550+ /// let user: User = user_resource.cloned_async().await;
551+ ///
552+ /// // Safe to use 'user' across async boundaries
553+ /// log_user_activity(user.id).await;
554+ ///
555+ /// // Return the cloned value for this resource
556+ /// user
557+ /// });
558+ ///
559+ /// rsx! {
560+ /// "Fetched User: {cloned_user:?}"
561+ /// }
562+ /// }
563+ /// # async fn fetch_user(_id: u32) -> User { User { id: 42, name: "Alice".to_string() } }
564+ /// # async fn log_user_activity(_id: u32) {}
565+ /// ```
566+ pub async fn cloned_async < ' a > ( & ' a self ) -> T
567+ where
568+ T : Clone ,
569+ {
570+ let mut read: generational_box:: GenerationalRef < std:: cell:: Ref < ' a , Option < T > > > =
571+ self . read ( ) ;
572+ while read. is_none ( ) {
573+ drop ( read) ;
574+ let _: ( ) = ( * self ) . await ;
575+ read = self . read ( ) ;
576+ }
577+ read. as_ref ( ) . unwrap ( ) . clone ( )
578+ }
579+
580+ /// Asynchronously wait for the resource to be ready and return a guard to its value, *without* subscribing the current component.
581+ ///
582+ /// This method is identical to `read_async`, but uses `peek()` internally instead of `read()`.
583+ /// This means the component rendering this code **will not** be re-rendered when the resource value changes.
584+ ///
585+ /// ## Important: Handling Guards Across Await Points
586+ ///
587+ /// Like `read_async`, **never hold the returned guard across await points.**
588+ /// You must drop the guard or clone the data before awaiting.
589+ ///
590+ /// ## Example
591+ ///
592+ /// Reading a prerequisite resource without causing a re-render:
593+ ///
594+ /// ```rust,no_run
595+ /// # use dioxus::prelude::*;
596+ /// #[derive(Clone, Debug)]
597+ /// struct Config { version: String }
598+ ///
599+ /// fn App() -> Element {
600+ /// let config_resource = use_resource(|| async { fetch_config().await });
601+ ///
602+ /// let final_data = use_resource(move || async move {
603+ /// // Use peek_async to wait for the config, but not subscribe this
604+ /// // resource's internal future to config_resource's changes.
605+ /// let config_guard = config_resource.peek_async().await;
606+ /// let version = config_guard.version.clone();
607+ /// drop(config_guard); // Drop guard
608+ ///
609+ /// // Now safe to proceed
610+ /// fetch_data_for_version(&version).await
611+ /// });
612+ ///
613+ /// rsx! { "Data: {final_data:?}" }
614+ /// }
615+ /// # async fn fetch_config() -> Config { Config { version: "v1".to_string() } }
616+ /// # async fn fetch_data_for_version(_v: &str) -> String { "Some Data".to_string() }
617+ /// ```
618+ pub async fn peek_async < ' a > (
619+ & ' a self ,
620+ ) -> generational_box:: GenerationalRef < std:: cell:: Ref < ' a , T > > {
621+ let mut peek: generational_box:: GenerationalRef < std:: cell:: Ref < ' a , Option < T > > > =
622+ self . peek ( ) ;
623+ while peek. is_none ( ) {
624+ drop ( peek) ;
625+ let _: ( ) = ( * self ) . await ;
626+ peek = self . peek ( ) ;
627+ }
628+ peek. map ( |e| std:: cell:: Ref :: map ( e, |option| option. as_ref ( ) . unwrap ( ) ) )
629+ }
524630}
525631
526632impl < T , E > Resource < Result < T , E > > {
0 commit comments