mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-27 06:30:20 +00:00
wip: upgrade hooks
This commit is contained in:
parent
c0e0196a67
commit
b3ac2ee3f7
10 changed files with 150 additions and 44 deletions
|
@ -32,3 +32,24 @@ or use `cargo-edit` to add it via the CLI:
|
||||||
```shell
|
```shell
|
||||||
$ cargo add dioxus --features desktop
|
$ 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
|
||||||
|
|
|
@ -3,14 +3,14 @@ use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
punctuated::Punctuated,
|
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 struct InlinePropsBody {
|
||||||
pub vis: syn::Visibility,
|
pub vis: syn::Visibility,
|
||||||
pub fn_token: Token![fn],
|
pub fn_token: Token![fn],
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
pub cx_token: Ident,
|
pub cx_token: Box<Pat>,
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
pub paren_token: token::Paren,
|
pub paren_token: token::Paren,
|
||||||
pub inputs: Punctuated<FnArg, Token![,]>,
|
pub inputs: Punctuated<FnArg, Token![,]>,
|
||||||
|
@ -31,9 +31,14 @@ impl Parse for InlinePropsBody {
|
||||||
let content;
|
let content;
|
||||||
let paren_token = syn::parenthesized!(content in input);
|
let paren_token = syn::parenthesized!(content in input);
|
||||||
|
|
||||||
let cx_token: Ident = content.parse()?;
|
let first_arg: FnArg = content.parse()?;
|
||||||
let _: Token![:] = content.parse()?;
|
let cx_token = {
|
||||||
let _: Ident = content.parse()?;
|
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 _: Result<Token![,]> = content.parse();
|
||||||
|
|
||||||
let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
|
let inputs = syn::punctuated::Punctuated::parse_terminated(&content)?;
|
||||||
|
@ -84,7 +89,7 @@ impl ToTokens for InlinePropsBody {
|
||||||
let modifiers = if generics.params.is_empty() {
|
let modifiers = if generics.params.is_empty() {
|
||||||
quote! { #[derive(Props, PartialEq)] }
|
quote! { #[derive(Props, PartialEq)] }
|
||||||
} else {
|
} else {
|
||||||
quote! { #[derive(PartialEq)] }
|
quote! { #[derive(Props)] }
|
||||||
};
|
};
|
||||||
|
|
||||||
out_tokens.append_all(quote! {
|
out_tokens.append_all(quote! {
|
||||||
|
@ -93,7 +98,7 @@ impl ToTokens for InlinePropsBody {
|
||||||
#(#fields),*
|
#(#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;
|
let #struct_name { #(#field_names),* } = &cx.props;
|
||||||
#block
|
#block
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,7 +702,7 @@ impl<'a> Future for PollTasks<'a> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::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 tasks = self.0.tasks.tasks.borrow_mut();
|
||||||
let mut to_remove = vec![];
|
let mut to_remove = vec![];
|
||||||
|
@ -712,7 +712,7 @@ impl<'a> Future for PollTasks<'a> {
|
||||||
if task.as_mut().poll(cx).is_ready() {
|
if task.as_mut().poll(cx).is_ready() {
|
||||||
to_remove.push(*id);
|
to_remove.push(*id);
|
||||||
} else {
|
} 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
|
// Resolve the future if any singular task is ready
|
||||||
match all_pending {
|
match any_pending {
|
||||||
true => Poll::Pending,
|
true => Poll::Pending,
|
||||||
false => Poll::Ready(()),
|
false => Poll::Ready(()),
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,5 +13,8 @@ pub use usecoroutine::*;
|
||||||
mod usefuture;
|
mod usefuture;
|
||||||
pub use usefuture::*;
|
pub use usefuture::*;
|
||||||
|
|
||||||
|
mod usesuspense;
|
||||||
|
pub use usesuspense::*;
|
||||||
|
|
||||||
// mod usemodel;
|
// mod usemodel;
|
||||||
// pub use usemodel::*;
|
// pub use usemodel::*;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use dioxus_core::ScopeState;
|
use dioxus_core::{ScopeState, TaskId};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::{cell::Cell, pin::Pin, rc::Rc};
|
use std::{cell::Cell, pin::Pin, rc::Rc};
|
||||||
/*
|
/*
|
||||||
|
@ -23,15 +23,17 @@ where
|
||||||
F: Future<Output = ()> + 'static,
|
F: Future<Output = ()> + 'static,
|
||||||
{
|
{
|
||||||
cx.use_hook(
|
cx.use_hook(
|
||||||
move |_| State {
|
move |_| {
|
||||||
running: Default::default(),
|
|
||||||
pending_fut: Default::default(),
|
|
||||||
running_fut: Default::default(),
|
|
||||||
},
|
|
||||||
|state| {
|
|
||||||
let f = create_future();
|
let f = create_future();
|
||||||
let id = cx.push_future(f);
|
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)));
|
// state.pending_fut.set(Some(Box::pin(f)));
|
||||||
|
|
||||||
// if let Some(fut) = state.running_fut.as_mut() {
|
// if let Some(fut) = state.running_fut.as_mut() {
|
||||||
|
@ -74,13 +76,13 @@ where
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
running: Rc<Cell<bool>>,
|
running: Rc<Cell<bool>>,
|
||||||
|
id: TaskId,
|
||||||
// the way this is structure, you can toggle the coroutine without re-rendering the comppnent
|
// 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
|
// 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
|
// todo: allocate pending futures in the bump allocator and then have a true promotion
|
||||||
pending_fut: Cell<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: Option<Pin<Box<dyn Future<Output = ()> + 'static>>>,
|
||||||
// running_fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>>,
|
// running_fut: Rc<RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CoroutineHandle<'a> {
|
pub struct CoroutineHandle<'a> {
|
||||||
|
@ -104,11 +106,11 @@ impl<'a> CoroutineHandle<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(submit) = self.inner.pending_fut.take() {
|
// if let Some(submit) = self.inner.pending_fut.take() {
|
||||||
// submit();
|
// submit();
|
||||||
// let inner = self.inner;
|
// let inner = self.inner;
|
||||||
// self.cx.push_task(submit());
|
// self.cx.push_task(submit());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&self) -> bool {
|
pub fn is_running(&self) -> bool {
|
||||||
|
|
|
@ -1,30 +1,52 @@
|
||||||
use dioxus_core::{ScopeState, TaskId};
|
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,
|
cx: &'a ScopeState,
|
||||||
f: impl FnOnce() -> F,
|
f: impl FnOnce() -> F,
|
||||||
) -> FutureHandle<'a, T> {
|
) -> (Option<&T>, FutureHandle<'a, T>) {
|
||||||
cx.use_hook(
|
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 {
|
UseFutureInner {
|
||||||
needs_regen: true,
|
needs_regen: true,
|
||||||
task: None,
|
slot,
|
||||||
|
value: None,
|
||||||
|
task: Some(task),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_| {
|
|state| {
|
||||||
//
|
if let Some(value) = state.slot.take() {
|
||||||
|
state.value = Some(value);
|
||||||
|
state.task = None;
|
||||||
|
}
|
||||||
|
(
|
||||||
|
state.value.as_ref(),
|
||||||
FutureHandle {
|
FutureHandle {
|
||||||
cx,
|
cx,
|
||||||
value: Cell::new(None),
|
value: Cell::new(None),
|
||||||
}
|
},
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UseFutureInner {
|
struct UseFutureInner<T> {
|
||||||
needs_regen: bool,
|
needs_regen: bool,
|
||||||
|
value: Option<T>,
|
||||||
|
slot: Rc<Cell<Option<T>>>,
|
||||||
task: Option<TaskId>,
|
task: Option<TaskId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -287,11 +287,16 @@ pub struct AsyncUseState<T: 'static> {
|
||||||
wip: Rc<RefCell<Option<T>>>,
|
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> {
|
pub fn get_mut<'a>(&'a self) -> RefMut<'a, T> {
|
||||||
// make sure we get processed
|
// 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
|
// 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
|
// "get_mut" is locked behind "ToOwned" to make it explicit that cloning occurs to use this
|
||||||
RefMut::map(self.wip.borrow_mut(), |slot| {
|
RefMut::map(self.wip.borrow_mut(), |slot| {
|
||||||
|
@ -305,9 +310,10 @@ impl<T> AsyncUseState<T> {
|
||||||
(self.re_render)();
|
(self.re_render)();
|
||||||
*self.wip.borrow_mut() = Some(val);
|
*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> {
|
pub fn get_rc(&self) -> &Rc<T> {
|
||||||
&self.inner
|
&self.inner
|
||||||
|
|
44
packages/hooks/src/usesuspense.rs
Normal file
44
packages/hooks/src/usesuspense.rs
Normal file
|
@ -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>,
|
||||||
|
}
|
|
@ -94,6 +94,8 @@ pub trait GlobalAttributes {
|
||||||
title;
|
title;
|
||||||
translate;
|
translate;
|
||||||
|
|
||||||
|
role;
|
||||||
|
|
||||||
/// dangerous_inner_html is Dioxus's replacement for using innerHTML in the browser DOM. In general, setting
|
/// 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)
|
/// 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
|
/// 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",
|
requiredFeatures: "requiredFeatures",
|
||||||
restart: "restart",
|
restart: "restart",
|
||||||
result: "result",
|
result: "result",
|
||||||
|
role: "role",
|
||||||
rotate: "rotate",
|
rotate: "rotate",
|
||||||
rx: "rx",
|
rx: "rx",
|
||||||
ry: "ry",
|
ry: "ry",
|
||||||
|
|
|
@ -209,7 +209,7 @@ pub mod events {
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use dioxus_core::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_elements::{GlobalAttributes, SvgAttributes};
|
||||||
pub use dioxus_hooks::*;
|
pub use dioxus_hooks::*;
|
||||||
pub use dioxus_html as dioxus_elements;
|
pub use dioxus_html as dioxus_elements;
|
||||||
|
|
Loading…
Reference in a new issue