Merge pull request #1984 from agreyyy/main

Add better documentation to use_future, use_resource, use_effect and use_context
This commit is contained in:
Evan Almloff 2024-02-28 08:55:38 -06:00 committed by GitHub
commit b58a3bb759
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 103 additions and 10 deletions

View file

@ -1,7 +1,7 @@
//! A simple example that shows how to use the use_future hook to run a background task.
//!
//! use_future assumes your future will never complete - it won't return a value.
//! If you want to return a value, use use_resource instead.
//! use_future won't return a value, analagous to use_effect.
//! If you want to return a value from a future, use use_resource instead.
use dioxus::prelude::*;
use std::time::Duration;

View file

@ -14,6 +14,18 @@ pub fn try_use_context<T: 'static + Clone>() -> Option<T> {
/// Consume some context in the tree, providing a sharable handle to the value
///
/// Does not regenerate the value if the value is changed at the parent.
/// ```rust
/// fn Parent() -> Element {
/// use_context_provider(|| Theme::Dark);
/// rsx! { Child {} }
/// }
/// #[component]
/// fn Child() -> Element {
/// //gets context provided by parent element with use_context_provider
/// let user_theme = use_context::<Theme>();
/// rsx! { "user using dark mode: {user_theme == Theme::Dark}" }
/// }
/// ```
#[must_use]
pub fn use_context<T: 'static + Clone>() -> T {
use_hook(|| consume_context::<T>())
@ -22,6 +34,24 @@ pub fn use_context<T: 'static + Clone>() -> T {
/// Provide some context via the tree and return a reference to it
///
/// Once the context has been provided, it is immutable. Mutations should be done via interior mutability.
/// Context can be read by any child components of the context provider, and is a solution to prop
/// drilling, using a context provider with a Signal inside is a good way to provide global/shared
/// state in your app:
/// ```rust
///fn app() -> Element {
/// use_context_provider(|| Signal::new(0));
/// rsx! { Child {} }
///}
/// // This component does read from the signal, so when the signal changes it will rerun
///#[component]
///fn Child() -> Element {
/// let signal: Signal<i32> = use_context();
/// rsx! {
/// button { onclick: move |_| signal += 1, "increment context" }
/// p {"{signal}"}
/// }
///}
/// ```
pub fn use_context_provider<T: 'static + Clone>(f: impl FnOnce() -> T) -> T {
use_hook(|| {
let val = f();

View file

@ -93,7 +93,8 @@ where
}
/// Get a handle to a coroutine higher in the tree
///
/// Analagous to use_context_provider and use_context,
/// but used for coroutines specifically
/// See the docs for [`use_coroutine`] for more details.
#[must_use]
pub fn use_coroutine_handle<M: 'static>() -> Coroutine<M> {

View file

@ -1,10 +1,22 @@
use dioxus_core::prelude::*;
use dioxus_signals::ReactiveContext;
/// Create a new effect. The effect will be run immediately and whenever any signal it reads changes.
/// The signal will be owned by the current component and will be dropped when the component is dropped.
///
/// `use_effect` will subscribe to any changes in the signal values it captures
/// effects will always run after first mount and then whenever the signal values change
/// If the use_effect call was skipped due to an early return, the effect will no longer activate.
/// ```rust
/// fn app() -> Element {
/// let mut count = use_signal(|| 0);
/// //the effect runs again each time count changes
/// use_effect(move || println!("Count changed to {count}"));
///
/// rsx! {
/// h1 { "High-Five counter: {count}" }
/// button { onclick: move |_| count += 1, "Up high!" }
/// button { onclick: move |_| count -= 1, "Down low!" }
/// }
/// }
/// ```
pub fn use_effect(mut callback: impl FnMut() + 'static) {
// let mut run_effect = use_hook(|| CopyValue::new(true));
// use_hook_did_run(move |did_run| run_effect.set(did_run));

View file

@ -8,10 +8,34 @@ use dioxus_signals::*;
use dioxus_signals::{Readable, Writable};
use std::future::Future;
/// A hook that allows you to spawn a future
///
/// A hook that allows you to spawn a future.
/// This future will **not** run on the server
/// The future is spawned on the next call to `flush_sync` which means that it will not run on the server.
/// To run a future on the server, you should use `spawn` directly.
/// `use_future` **won't return a value**.
/// If you want to return a value from a future, use `use_resource` instead.
/// ```rust
/// fn app() -> Element {
/// let mut count = use_signal(|| 0);
/// let mut running = use_signal(|| true);
/// // `use_future` will spawn an infinitely running future that can be started and stopped
/// use_future(move || async move {
/// loop {
/// if running() {
/// count += 1;
/// }
/// tokio::time::sleep(Duration::from_millis(400)).await;
/// }
/// });
/// rsx! {
/// div {
/// h1 { "Current count: {count}" }
/// button { onclick: move |_| running.toggle(), "Start/Stop the count"}
/// button { onclick: move |_| count.set(0), "Reset the count" }
/// }
/// }
/// }
/// ```
pub fn use_future<F>(mut future: impl FnMut() -> F + 'static) -> UseFuture
where
F: Future + 'static,

View file

@ -10,8 +10,32 @@ use futures_util::{future, pin_mut, FutureExt};
use std::future::Future;
/// A memo that resolve to a value asynchronously.
/// Unlike `use_future`, `use_resource` runs on the **server**
/// See [`Resource`] for more details.
/// ```rust
///fn app() -> Element {
/// let country = use_signal(|| WeatherLocation {
/// city: "Berlin".to_string(),
/// country: "Germany".to_string(),
/// coordinates: (52.5244, 13.4105)
/// });
///
/// This runs on the server
/// let current_weather = //run a future inside the use_resource hook
/// use_resource(move || async move { get_weather(&country.read().clone()).await });
///
/// rsx! {
/// //the value of the future can be polled to
/// //conditionally render elements based off if the future
/// //finished (Some(Ok(_)), errored Some(Err(_)),
/// //or is still finishing (None)
/// match current_weather.value() {
/// Some(Ok(weather)) => WeatherElement { weather },
/// Some(Err(e)) => p { "Loading weather failed, {e}" }
/// None => p { "Loading..." }
/// }
/// }
///}
/// ```
#[must_use = "Consider using `cx.spawn` to run a future without reading its value"]
pub fn use_resource<T, F>(future: impl Fn() -> F + 'static) -> Resource<T>
where

View file

@ -39,7 +39,9 @@ pub trait Readable {
MappedSignal::new(try_read, peek)
}
/// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal. If the value has been dropped, this will panic.
/// Get the current value of the state. If this is a signal, this will subscribe the current scope to the signal.
/// If the value has been dropped, this will panic. Calling this on a Signal is the same as
/// using the signal() syntax to read and subscribe to its value
#[track_caller]
fn read(&self) -> ReadableRef<Self> {
self.try_read().unwrap()