瀏覽代碼

added better documentation and code snipppets for the use_resource, use_future, use_effect and use_context hooks

andrey 1 年之前
父節點
當前提交
df0d45be48

+ 27 - 0
packages/hooks/src/use_context.rs

@@ -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,21 @@ 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! { "{signal}" }
+///}
+/// ```
 pub fn use_context_provider<T: 'static + Clone>(f: impl FnOnce() -> T) -> T {
     use_hook(|| {
         let val = f();

+ 2 - 1
packages/hooks/src/use_coroutine.rs

@@ -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> {

+ 15 - 3
packages/hooks/src/use_effect.rs

@@ -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));

+ 24 - 0
packages/hooks/src/use_future.rs

@@ -12,6 +12,30 @@ use std::future::Future;
 ///
 /// 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 assumes your future will never complete - **it won't return a value**.
+/// If you want to return a value, 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,

+ 25 - 1
packages/hooks/src/use_resource.rs

@@ -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

+ 1 - 0
packages/signals/src/impls.rs

@@ -5,6 +5,7 @@ use crate::write::Writable;
 use crate::{GlobalMemo, GlobalSignal, MappedSignal, ReadOnlySignal, SignalData};
 use generational_box::{AnyStorage, Storage};
 
+use std::ops::Index;
 use std::{
     fmt::{Debug, Display},
     ops::{Add, Div, Mul, Sub},

+ 2 - 2
packages/signals/src/signal.rs

@@ -10,8 +10,8 @@ use generational_box::{AnyStorage, Storage, SyncStorage, UnsyncStorage};
 use std::{
     any::Any,
     collections::HashSet,
-    ops::{Deref, DerefMut},
-    sync::Mutex,
+    ops::{Deref, DerefMut, Index, IndexMut},
+    sync::{Arc, Mutex},
 };
 
 /// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.

+ 3 - 0
packages/signals/tests/create.rs

@@ -1,5 +1,8 @@
 #![allow(unused, non_upper_case_globals, non_snake_case)]
 
+use std::collections::HashMap;
+use std::sync::Arc;
+
 use dioxus::prelude::*;
 use dioxus_core::ElementId;
 use dioxus_core::NoOpMutations;