Feat: add global context functions

Add functions like window() and router() to
allow dynamically grabbing global contexts
without have to use the hook variants.

Deprecates the existing hook variants to
discourage folks from adding more noise
to their codebases.
This commit is contained in:
Jonathan Kelley 2023-10-23 16:26:10 -04:00
parent cea9563e25
commit dd4547d753
No known key found for this signature in database
GPG key ID: 1FBB50F7EB0A08BE
16 changed files with 77 additions and 78 deletions

View file

@ -1,18 +0,0 @@
use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
cx.render(rsx! {
button {
onclick: |_| async move {
println!("hello, desktop!");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("goodbye, desktop!");
},
"hello, desktop!"
}
})
}

View file

@ -1,7 +1,6 @@
//! This example shows how to create a popup window and send data back to the parent window.
use dioxus::prelude::*;
use dioxus_desktop::use_window;
use futures_util::StreamExt;
fn main() {
@ -9,7 +8,6 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let window = use_window(cx);
let emails_sent = use_ref(cx, Vec::new);
let tx = use_coroutine(cx, |mut rx: UnboundedReceiver<String>| {
@ -34,7 +32,7 @@ fn app(cx: Scope) -> Element {
// this returns a weak reference to the other window
// Be careful not to keep a strong reference to the other window or it will never be dropped
// and the window will never close.
window.new_window(dom, Default::default());
dioxus_desktop::window().new_window(dom, Default::default());
},
"Click to compose a new email"
}
@ -57,7 +55,6 @@ struct ComposeProps {
fn compose(cx: Scope<ComposeProps>) -> Element {
let user_input = use_state(cx, String::new);
let window = use_window(cx);
cx.render(rsx! {
div {
@ -66,15 +63,13 @@ fn compose(cx: Scope<ComposeProps>) -> Element {
button {
onclick: move |_| {
cx.props.app_tx.send(user_input.get().clone());
window.close();
dioxus_desktop::window().close();
},
"Click to send"
}
input {
oninput: move |e| {
user_input.set(e.value.clone());
},
oninput: move |e| user_input.set(e.value.clone()),
value: "{user_input}"
}
}

View file

@ -87,8 +87,6 @@ fn ClientAdd(cx: Scope) -> Element {
let last_name = use_state(cx, String::new);
let description = use_state(cx, String::new);
let navigator = use_navigator(cx);
cx.render(rsx! {
h2 { "Add new Client" }
@ -103,7 +101,7 @@ fn ClientAdd(cx: Scope) -> Element {
description: description.to_string(),
});
navigator.push(Route::ClientList {});
dioxus_router::router().push(Route::ClientList {});
},
fieldset {

View file

@ -5,26 +5,21 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let eval_provider = use_eval(cx);
let future = use_future(cx, (), |_| {
to_owned![eval_provider];
async move {
let eval = eval_provider(
r#"
let future = use_future(cx, (), |_| async move {
let eval = eval(
r#"
dioxus.send("Hi from JS!");
let msg = await dioxus.recv();
console.log(msg);
return "hello world";
"#,
)
.unwrap();
)
.unwrap();
eval.send("Hi from Rust!".into()).unwrap();
let res = eval.recv().await.unwrap();
println!("{:?}", eval.await);
res
}
eval.send("Hi from Rust!".into()).unwrap();
let res = eval.recv().await.unwrap();
println!("{:?}", eval.await);
res
});
match future.value() {

View file

@ -8,27 +8,25 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let onsubmit = move |evt: FormEvent| {
cx.spawn(async move {
let resp = reqwest::Client::new()
.post("http://localhost:8080/login")
.form(&[
("username", &evt.values["username"]),
("password", &evt.values["password"]),
])
.send()
.await;
let onsubmit = move |evt: FormEvent| async move {
let resp = reqwest::Client::new()
.post("http://localhost:8080/login")
.form(&[
("username", &evt.values["username"]),
("password", &evt.values["password"]),
])
.send()
.await;
match resp {
// Parse data from here, such as storing a response token
Ok(_data) => println!("Login successful!"),
match resp {
// Parse data from here, such as storing a response token
Ok(_data) => println!("Login successful!"),
//Handle any errors from the fetch here
Err(_err) => {
println!("Login failed - you need a login server running on localhost:8080.")
}
//Handle any errors from the fetch here
Err(_err) => {
println!("Login failed - you need a login server running on localhost:8080.")
}
});
}
};
cx.render(rsx! {

View file

@ -5,14 +5,12 @@ fn main() {
}
fn app(cx: Scope) -> Element {
let window = dioxus_desktop::use_window(cx);
cx.render(rsx! {
div {
button {
onclick: move |_| {
let dom = VirtualDom::new(popup);
window.new_window(dom, Default::default());
dioxus_desktop::window().new_window(dom, Default::default());
},
"New Window"
}

View file

@ -1,13 +1,11 @@
use dioxus::prelude::*;
use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, LogicalSize, WindowBuilder};
use dioxus_desktop::{tao::dpi::PhysicalPosition, LogicalSize, WindowBuilder};
fn main() {
dioxus_desktop::launch_cfg(app, make_config());
}
fn app(cx: Scope) -> Element {
let window = use_window(cx);
cx.render(rsx! {
div {
width: "100%",
@ -19,7 +17,7 @@ fn app(cx: Scope) -> Element {
width: "100%",
height: "10px",
background_color: "black",
onmousedown: move |_| window.drag(),
onmousedown: move |_| dioxus_desktop::window().drag(),
}
"This is an overlay!"

View file

@ -1,12 +1,10 @@
use dioxus::prelude::*;
use dioxus_desktop::use_window;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let window = use_window(cx);
let level = use_state(cx, || 1.0);
cx.render(rsx! {
@ -16,7 +14,7 @@ fn app(cx: Scope) -> Element {
oninput: |e| {
if let Ok(new_zoom) = e.value.parse::<f64>() {
level.set(new_zoom);
window.webview.zoom(new_zoom);
dioxus_desktop::window().webview.zoom(new_zoom);
}
}
}

View file

@ -28,6 +28,15 @@ use wry::webview::WebView;
pub type ProxyType = EventLoopProxy<UserWindowEvent>;
/// Get an imperative handle to the current window without using a hook
///
/// ## Panics
///
/// This function will panic if it is called outside of the context of a Dioxus App.
pub fn window() -> DesktopContext {
dioxus_core::prelude::consume_context().unwrap()
}
/// Get an imperative handle to the current window
pub fn use_window(cx: &ScopeState) -> &DesktopContext {
cx.use_hook(|| cx.consume_context::<DesktopContext>())

View file

@ -23,7 +23,7 @@ use crate::query::QueryResult;
pub use cfg::{Config, WindowCloseBehaviour};
pub use desktop_context::DesktopContext;
pub use desktop_context::{
use_window, use_wry_event_handler, DesktopService, WryEventHandler, WryEventHandlerId,
use_window, use_wry_event_handler, window, DesktopService, WryEventHandler, WryEventHandlerId,
};
use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers};
use dioxus_core::*;

View file

@ -48,6 +48,15 @@ pub fn use_eval(cx: &ScopeState) -> &EvalCreator {
})
}
pub fn eval(script: &str) -> Result<UseEval, EvalError> {
let eval_provider = dioxus_core::prelude::consume_context::<Rc<dyn EvalProvider>>()
.expect("evaluator not provided");
eval_provider
.new_evaluator(script.to_string())
.map(UseEval::new)
}
/// A wrapper around the target platform's evaluator.
#[derive(Clone)]
pub struct UseEval {

View file

@ -66,7 +66,6 @@ fn Route2(cx: Scope, user_id: usize) -> Element {
#[component]
fn Route3(cx: Scope, dynamic: String) -> Element {
let navigator = use_navigator(cx);
let current_route = use_route(cx)?;
let current_route_str = use_ref(cx, String::new);
let parsed = Route::from_str(&current_route_str.read());
@ -78,9 +77,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
render! {
input {
oninput: move |evt| {
*current_route_str.write() = evt.value.clone();
},
oninput: move |evt| *current_route_str.write() = evt.value.clone(),
value: "{current_route_str.read()}"
}
"dynamic: {dynamic}"
@ -89,7 +86,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
"hello world link"
}
button {
onclick: move |_| { navigator.push("https://www.google.com"); },
onclick: move |_| { dioxus_router::router().push("https://www.google.com"); },
"google link"
}
p { "Site Map" }

View file

@ -1,5 +1,19 @@
use crate::prelude::{ExternalNavigationFailure, IntoRoutable, RouterContext};
/// Acquire the navigator without subscribing to updates.
///
/// Can be called anywhere in the application provided a Router has been initialized.
///
/// ## Panics
///
/// Panics if there is no router present.
pub fn navigator() -> Navigator {
Navigator(
dioxus::core::prelude::consume_context::<RouterContext>()
.expect("A router must be present to use navigator"),
)
}
/// A view into the navigation state of a router.
#[derive(Clone)]
pub struct Navigator(pub(crate) RouterContext);

View file

@ -49,6 +49,7 @@ use crate::prelude::{Navigator, RouterContext};
/// # let _ = vdom.rebuild();
/// ```
#[must_use]
#[deprecated = "Prefer acquiring the router directly with `dioxus_router::router()`"]
pub fn use_navigator(cx: &ScopeState) -> &Navigator {
&*cx.use_hook(|| {
let router = cx

View file

@ -2,7 +2,7 @@ use dioxus::prelude::ScopeState;
use crate::{prelude::RouterContext, utils::use_router_internal::use_router_internal};
#[deprecated = "prefer the use_navigator or use_route functions"]
#[deprecated = "prefer the `router()` function or `use_route` functions"]
#[must_use]
/// A hook that provides access to information about the router.
pub fn use_router(cx: &ScopeState) -> &RouterContext {
@ -10,3 +10,8 @@ pub fn use_router(cx: &ScopeState) -> &RouterContext {
.as_ref()
.expect("use_route must have access to a router")
}
/// Aquire the router without subscribing to updates.
pub fn router() -> RouterContext {
dioxus::core::prelude::consume_context().unwrap()
}

View file

@ -53,6 +53,8 @@ pub mod hooks {
pub use use_navigator::*;
}
pub use hooks::router;
/// A collection of useful items most applications might need.
pub mod prelude {
pub use crate::components::*;