Kaynağa Gözat

wip: upgrade hooks

Jonathan Kelley 3 yıl önce
ebeveyn
işleme
b3ac2ee3f7

+ 21 - 0
docs/guide/src/tutorial/new_app.md

@@ -32,3 +32,24 @@ or use `cargo-edit` to add it via the CLI:
 ```shell
 $ cargo add dioxus --features desktop
 ```
+
+## Setting up a hello world
+
+Let's edit the project's `main.rs` and add the skeleton of 
+
+```rust
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx!(
+        div { "hello world!" }
+    ))
+}
+```
+
+
+## Making sure things run

+ 12 - 7
packages/core-macro/src/inlineprops.rs

@@ -3,14 +3,14 @@ use quote::{quote, ToTokens, TokenStreamExt};
 use syn::{
     parse::{Parse, ParseStream},
     punctuated::Punctuated,
-    token, Block, FnArg, Generics, Ident, Result, ReturnType, Token, Visibility,
+    token, Block, FnArg, Generics, Ident, Pat, Result, ReturnType, Token, Visibility,
 };
 
 pub struct InlinePropsBody {
     pub vis: syn::Visibility,
     pub fn_token: Token![fn],
     pub ident: Ident,
-    pub cx_token: Ident,
+    pub cx_token: Box<Pat>,
     pub generics: Generics,
     pub paren_token: token::Paren,
     pub inputs: Punctuated<FnArg, Token![,]>,
@@ -31,9 +31,14 @@ impl Parse for InlinePropsBody {
         let content;
         let paren_token = syn::parenthesized!(content in input);
 
-        let cx_token: Ident = content.parse()?;
-        let _: Token![:] = content.parse()?;
-        let _: Ident = content.parse()?;
+        let first_arg: FnArg = content.parse()?;
+        let cx_token = {
+            match first_arg {
+                FnArg::Receiver(_) => panic!("first argument must not be  a reciver argument"),
+                FnArg::Typed(f) => f.pat,
+            }
+        };
+
         let _: Result<Token![,]> = content.parse();
 
         let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
@@ -84,7 +89,7 @@ impl ToTokens for InlinePropsBody {
         let modifiers = if generics.params.is_empty() {
             quote! { #[derive(Props, PartialEq)] }
         } else {
-            quote! { #[derive(PartialEq)] }
+            quote! { #[derive(Props)] }
         };
 
         out_tokens.append_all(quote! {
@@ -93,7 +98,7 @@ impl ToTokens for InlinePropsBody {
                 #(#fields),*
             }
 
-            #vis fn #ident #generics (#cx_token: Scope<#struct_name>) #output {
+            #vis fn #ident #generics (#cx_token: Scope<'a, #struct_name #generics>) #output {
                 let #struct_name { #(#field_names),* } = &cx.props;
                 #block
             }

+ 3 - 3
packages/core/src/virtual_dom.rs

@@ -702,7 +702,7 @@ impl<'a> Future for PollTasks<'a> {
     type Output = ();
 
     fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
-        let mut all_pending = true;
+        let mut any_pending = false;
 
         let mut tasks = self.0.tasks.tasks.borrow_mut();
         let mut to_remove = vec![];
@@ -712,7 +712,7 @@ impl<'a> Future for PollTasks<'a> {
             if task.as_mut().poll(cx).is_ready() {
                 to_remove.push(*id);
             } else {
-                all_pending = false;
+                any_pending = true;
             }
         }
 
@@ -721,7 +721,7 @@ impl<'a> Future for PollTasks<'a> {
         }
 
         // Resolve the future if any singular task is ready
-        match all_pending {
+        match any_pending {
             true => Poll::Pending,
             false => Poll::Ready(()),
         }

+ 3 - 0
packages/hooks/src/lib.rs

@@ -13,5 +13,8 @@ pub use usecoroutine::*;
 mod usefuture;
 pub use usefuture::*;
 
+mod usesuspense;
+pub use usesuspense::*;
+
 // mod usemodel;
 // pub use usemodel::*;

+ 19 - 17
packages/hooks/src/usecoroutine.rs

@@ -1,4 +1,4 @@
-use dioxus_core::ScopeState;
+use dioxus_core::{ScopeState, TaskId};
 use std::future::Future;
 use std::{cell::Cell, pin::Pin, rc::Rc};
 /*
@@ -23,15 +23,17 @@ where
     F: Future<Output = ()> + 'static,
 {
     cx.use_hook(
-        move |_| State {
-            running: Default::default(),
-            pending_fut: Default::default(),
-            running_fut: Default::default(),
-        },
-        |state| {
+        move |_| {
             let f = create_future();
             let id = cx.push_future(f);
-
+            State {
+                running: Default::default(),
+                id
+                // pending_fut: Default::default(),
+                // running_fut: Default::default(),
+            }
+        },
+        |state| {
             // state.pending_fut.set(Some(Box::pin(f)));
 
             // if let Some(fut) = state.running_fut.as_mut() {
@@ -74,13 +76,13 @@ where
 
 struct State {
     running: Rc<Cell<bool>>,
-
+    id: TaskId,
     // the way this is structure, you can toggle the coroutine without re-rendering the comppnent
     // this means every render *generates* the future, which is a bit of a waste
     // todo: allocate pending futures in the bump allocator and then have a true promotion
-    pending_fut: Cell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
-    running_fut: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
-    // running_fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>>,
+    // pending_fut: Cell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
+    // running_fut: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
+    // running_fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>>
 }
 
 pub struct CoroutineHandle<'a> {
@@ -104,11 +106,11 @@ impl<'a> CoroutineHandle<'a> {
             return;
         }
 
-        if let Some(submit) = self.inner.pending_fut.take() {
-            // submit();
-            // let inner = self.inner;
-            // self.cx.push_task(submit());
-        }
+        // if let Some(submit) = self.inner.pending_fut.take() {
+        // submit();
+        // let inner = self.inner;
+        // self.cx.push_task(submit());
+        // }
     }
 
     pub fn is_running(&self) -> bool {

+ 32 - 10
packages/hooks/src/usefuture.rs

@@ -1,30 +1,52 @@
 use dioxus_core::{ScopeState, TaskId};
-use std::{cell::Cell, future::Future};
+use std::{cell::Cell, future::Future, rc::Rc};
 
-pub fn use_future<'a, T: 'static, F: Future<Output = T>>(
+pub fn use_future<'a, T: 'static, F: Future<Output = T> + 'static>(
     cx: &'a ScopeState,
     f: impl FnOnce() -> F,
-) -> FutureHandle<'a, T> {
+) -> (Option<&T>, FutureHandle<'a, T>) {
     cx.use_hook(
         |_| {
             //
+            let fut = f();
+            let slot = Rc::new(Cell::new(None));
+            let updater = cx.schedule_update();
+
+            let _slot = slot.clone();
+            let new_fut = async move {
+                let res = fut.await;
+                _slot.set(Some(res));
+                updater();
+            };
+            let task = cx.push_future(new_fut);
+
             UseFutureInner {
                 needs_regen: true,
-                task: None,
+                slot,
+                value: None,
+                task: Some(task),
             }
         },
-        |_| {
-            //
-            FutureHandle {
-                cx,
-                value: Cell::new(None),
+        |state| {
+            if let Some(value) = state.slot.take() {
+                state.value = Some(value);
+                state.task = None;
             }
+            (
+                state.value.as_ref(),
+                FutureHandle {
+                    cx,
+                    value: Cell::new(None),
+                },
+            )
         },
     )
 }
 
-struct UseFutureInner {
+struct UseFutureInner<T> {
     needs_regen: bool,
+    value: Option<T>,
+    slot: Rc<Cell<Option<T>>>,
     task: Option<TaskId>,
 }
 

+ 12 - 6
packages/hooks/src/usestate.rs

@@ -287,11 +287,16 @@ pub struct AsyncUseState<T: 'static> {
     wip: Rc<RefCell<Option<T>>>,
 }
 
-impl<T: ToOwned> AsyncUseState<T> {
+impl<T: ToOwned<Owned = T>> AsyncUseState<T> {
     pub fn get_mut<'a>(&'a self) -> RefMut<'a, T> {
         // make sure we get processed
-        // self.needs_update();
-
+        {
+            let mut wip = self.wip.borrow_mut();
+            if wip.is_none() {
+                *wip = Some(self.inner.as_ref().to_owned());
+            }
+            (self.re_render)();
+        }
         // Bring out the new value, cloning if it we need to
         // "get_mut" is locked behind "ToOwned" to make it explicit that cloning occurs to use this
         RefMut::map(self.wip.borrow_mut(), |slot| {
@@ -305,9 +310,10 @@ impl<T> AsyncUseState<T> {
         (self.re_render)();
         *self.wip.borrow_mut() = Some(val);
     }
-    pub fn get(&self) -> &T {
-        self.inner.as_ref()
-    }
+
+    // pub fn get(&self) -> Ref<'_, T> {
+    //     self.wip.borrow
+    // }
 
     pub fn get_rc(&self) -> &Rc<T> {
         &self.inner

+ 44 - 0
packages/hooks/src/usesuspense.rs

@@ -0,0 +1,44 @@
+use std::{cell::Cell, future::Future, rc::Rc};
+
+use dioxus_core::{Element, ScopeState, TaskId};
+
+pub fn use_suspense<R: 'static, F: Future<Output = R> + 'static>(
+    cx: &ScopeState,
+    create_future: impl FnOnce() -> F,
+    render: impl FnOnce(&R) -> Element,
+) -> Element {
+    cx.use_hook(
+        |_| {
+            let fut = create_future();
+
+            let wip_value: Rc<Cell<Option<R>>> = Default::default();
+
+            let wip = wip_value.clone();
+            let new_fut = async move {
+                let val = fut.await;
+                wip.set(Some(val));
+            };
+
+            let task = cx.push_future(new_fut);
+            SuspenseInner {
+                task,
+                value: None,
+                wip_value,
+            }
+        },
+        |sus| {
+            if let Some(value) = sus.value.as_ref() {
+                render(&value)
+            } else {
+                // generate a placeholder node if the future isnt ready
+                None
+            }
+        },
+    )
+}
+
+struct SuspenseInner<R> {
+    task: TaskId,
+    wip_value: Rc<Cell<Option<R>>>,
+    value: Option<R>,
+}

+ 3 - 0
packages/html/src/global_attributes.rs

@@ -94,6 +94,8 @@ pub trait GlobalAttributes {
         title;
         translate;
 
+        role;
+
         /// dangerous_inner_html is Dioxus's replacement for using innerHTML in the browser DOM. In general, setting
         /// HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS)
         /// attack. So, you can set HTML directly from Dioxus, but you have to type out dangerous_inner_html to remind
@@ -838,6 +840,7 @@ pub trait SvgAttributes {
         requiredFeatures: "requiredFeatures",
         restart: "restart",
         result: "result",
+        role: "role",
         rotate: "rotate",
         rx: "rx",
         ry: "ry",

+ 1 - 1
src/lib.rs

@@ -209,7 +209,7 @@ pub mod events {
 
 pub mod prelude {
     pub use dioxus_core::prelude::*;
-    pub use dioxus_core_macro::{format_args_f, rsx, Props, Routable};
+    pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props, Routable};
     pub use dioxus_elements::{GlobalAttributes, SvgAttributes};
     pub use dioxus_hooks::*;
     pub use dioxus_html as dioxus_elements;