Improve inline docs (#2460)
Improve inline docs * improve incorrect event handler return error message * Improve event handler docs * document the eval functions * document spawn and common spawn errors * fix event handler docs * add notes about how you use attributes and elements in rsx * add doc aliases for attributes and events we rename * add some more aliases for common search terms * don't doc ignore any public examples in core * don't ignore public doc examples in ssr * don't ignore examples in the dioxus package readme * add a warning when you launch without a renderer enabled * fix some outdated element docs * add a bunch of examples to resource * add notes about desktop events * add more docs for use_resource * add on_unimplemented hint to Dependency * fix some unresolved links * add examples to each of the router traits * add not implemented errors for router traits * add an example to the routable trait * expand rsx macro docs * improve memo docs * update the dioxus readme * mention dioxus crate features in the docs * fix a bunch of doc tests * fix html doc tests * fix router doc tests * fix dioxus signals doc tests * fix dioxus ssr doc tests * fix use_future example in the hooks cheat sheet * add a javascript alias for eval * fix hook explanation values * remove unused embed-doc-image dependency
This commit is contained in:
1 parent
054351139f
commit
0127501dbf
71 files changed
+4132
-1162
No files matched your search
@@ -114,6 +114,11 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
|
||||
pub fn id(&self) -> GenerationalBoxId {
|
||||
self.value.id()
|
||||
}
|
||||
|
||||
/// Get the underlying [`GenerationalBox`] value.
|
||||
pub fn value(&self) -> GenerationalBox<T, S> {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
|
||||
|
||||
@@ -17,7 +17,10 @@ struct UpdateInformation<T> {
|
||||
callback: RefCell<Box<dyn FnMut() -> T>>,
|
||||
}
|
||||
|
||||
/// A value that is memoized. This is useful for caching the result of a computation.
|
||||
#[doc = include_str!("../docs/memo.md")]
|
||||
#[doc(alias = "Selector")]
|
||||
#[doc(alias = "UseMemo")]
|
||||
#[doc(alias = "Memorize")]
|
||||
pub struct Memo<T: 'static> {
|
||||
inner: Signal<T>,
|
||||
update: CopyValue<UpdateInformation<T>>,
|
||||
|
||||
@@ -7,12 +7,7 @@ use std::{cell::RefCell, hash::Hash};
|
||||
|
||||
use crate::{CopyValue, Writable};
|
||||
|
||||
/// A context for signal reads and writes to be directed to
|
||||
///
|
||||
/// When a signal calls .read(), it will look for the current ReactiveContext to read from.
|
||||
/// If it doesn't find it, then it will try and insert a context into the nearest component scope via context api.
|
||||
///
|
||||
/// When the ReactiveContext drops, it will remove itself from the associated contexts attached to signal
|
||||
#[doc = include_str!("../docs/reactivity.md")]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ReactiveContext {
|
||||
inner: CopyValue<Inner, SyncStorage>,
|
||||
|
||||
@@ -10,6 +10,30 @@ pub type ReadableRef<'a, T: Readable, O = <T as Readable>::Target> =
|
||||
<T::Storage as AnyStorage>::Ref<'a, O>;
|
||||
|
||||
/// A trait for states that can be read from like [`crate::Signal`], [`crate::GlobalSignal`], or [`crate::ReadOnlySignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Readable`] type.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn double(something_readable: &impl Readable<Target = i32>) -> i32 {
|
||||
/// something_readable.cloned() * 2
|
||||
/// }
|
||||
///
|
||||
/// static COUNT: GlobalSignal<i32> = Signal::global(|| 0);
|
||||
///
|
||||
/// fn MyComponent(count: Signal<i32>) -> Element {
|
||||
/// // Since we defined the function in terms of the readable trait, we can use it with any readable type (Signal, GlobalSignal, ReadOnlySignal, etc)
|
||||
/// let doubled = use_memo(move || double(&count));
|
||||
/// let global_count_doubled = use_memo(|| double(&COUNT));
|
||||
/// rsx! {
|
||||
/// div {
|
||||
/// "Count local: {count}"
|
||||
/// "Doubled local: {doubled}"
|
||||
/// "Count global: {COUNT}"
|
||||
/// "Doubled global: {global_count_doubled}"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Readable {
|
||||
/// The target type of the reference.
|
||||
type Target: ?Sized + 'static;
|
||||
@@ -17,7 +41,30 @@ pub trait Readable {
|
||||
/// The type of the storage this readable uses.
|
||||
type Storage: AnyStorage;
|
||||
|
||||
/// Map the readable type to a new type.
|
||||
/// Map the readable type to a new type. This lets you provide a view into a readable type without needing to clone the inner value.
|
||||
///
|
||||
/// Anything that subscribes to the readable value will be rerun whenever the original value changes, even if the view does not change. If you want to memorize the view, you can use a [`crate::Memo`] instead.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn List(list: Signal<Vec<i32>>) -> Element {
|
||||
/// rsx! {
|
||||
/// for index in 0..list.len() {
|
||||
/// // We can use the `map` method to provide a view into the single item in the list that the child component will render
|
||||
/// Item { item: list.map(move |v| &v[index]) }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // The child component doesn't need to know that the mapped value is coming from a list
|
||||
/// #[component]
|
||||
/// fn Item(item: MappedSignal<i32>) -> Element {
|
||||
/// rsx! {
|
||||
/// div { "Item: {item}" }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn map<O>(self, f: impl Fn(&Self::Target) -> &O + 'static) -> MappedSignal<O, Self::Storage>
|
||||
where
|
||||
Self: Clone + Sized + 'static,
|
||||
@@ -80,6 +127,38 @@ pub trait Readable {
|
||||
fn peek_unchecked(&self) -> ReadableRef<'static, Self>;
|
||||
|
||||
/// Get the current value of the state without subscribing to updates. If the value has been dropped, this will panic.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn MyComponent(mut count: Signal<i32>) -> Element {
|
||||
/// let mut event_source = use_signal(|| None);
|
||||
/// let doubled = use_memo(move || {
|
||||
/// // We want to log the value of the event_source, but we don't need to rerun the doubled value if the event_source changes (because the value of doubled doesn't depend on the event_source)
|
||||
/// // We can read the value with peek without subscribing to updates
|
||||
/// let click_count = count.peek();
|
||||
/// tracing::info!("Click count: {click_count:?}");
|
||||
/// count() * 2
|
||||
/// });
|
||||
/// rsx! {
|
||||
/// div { "Count: {count}" }
|
||||
/// div { "Doubled: {doubled}" }
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// event_source.set(Some("Click me button"));
|
||||
/// },
|
||||
/// "Click me"
|
||||
/// }
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// event_source.set(Some("Double me button"));
|
||||
/// count += 1;
|
||||
/// },
|
||||
/// "Double me"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[track_caller]
|
||||
fn peek(&self) -> ReadableRef<Self> {
|
||||
Self::Storage::downcast_lifetime_ref(self.peek_unchecked())
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
use crate::{default_impl, fmt_impls, write_impls};
|
||||
use crate::{
|
||||
read::Readable, write::Writable, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext,
|
||||
ReadableRef,
|
||||
};
|
||||
use crate::{read::*, write::*, CopyValue, GlobalMemo, GlobalSignal, ReactiveContext, ReadableRef};
|
||||
use crate::{Memo, WritableRef};
|
||||
use dioxus_core::IntoDynNode;
|
||||
use dioxus_core::{prelude::IntoAttributeValue, ScopeId};
|
||||
@@ -14,41 +11,19 @@ use std::{
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_signals::*;
|
||||
///
|
||||
/// #[component]
|
||||
/// fn App() -> Element {
|
||||
/// let mut count = use_signal(|| 0);
|
||||
///
|
||||
/// // Because signals have automatic dependency tracking, if you never read them in a component, that component will not be re-rended when the signal is updated.
|
||||
/// // The app component will never be rerendered in this example.
|
||||
/// rsx! { Child { state: count } }
|
||||
/// }
|
||||
///
|
||||
/// #[component]
|
||||
/// fn Child(mut state: Signal<u32>) -> Element {
|
||||
/// use_future(move || async move {
|
||||
/// // Because the signal is a Copy type, we can use it in an async block without cloning it.
|
||||
/// state += 1;
|
||||
/// });
|
||||
///
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// onclick: move |_| state += 1,
|
||||
/// "{state}"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[doc = include_str!("../docs/signals.md")]
|
||||
#[doc(alias = "State")]
|
||||
#[doc(alias = "UseState")]
|
||||
#[doc(alias = "UseRef")]
|
||||
pub struct Signal<T: 'static, S: Storage<SignalData<T>> = UnsyncStorage> {
|
||||
pub(crate) inner: CopyValue<SignalData<T>, S>,
|
||||
}
|
||||
|
||||
/// A signal that can safely shared between threads.
|
||||
#[doc(alias = "SendSignal")]
|
||||
#[doc(alias = "UseRwLock")]
|
||||
#[doc(alias = "UseRw")]
|
||||
#[doc(alias = "UseMutex")]
|
||||
pub type SyncSignal<T> = Signal<T, SyncStorage>;
|
||||
|
||||
/// The data stored for tracking in a signal.
|
||||
@@ -58,7 +33,24 @@ pub struct SignalData<T> {
|
||||
}
|
||||
|
||||
impl<T: 'static> Signal<T> {
|
||||
/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
|
||||
/// Creates a new [`Signal`]. Signals are a Copy state management solution with automatic dependency tracking.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// This function should generally only be called inside hooks. The signal that this function creates is owned by the current component and will only be dropped when the component is dropped. If you call this function outside of a hook many times, you will leak memory until the component is dropped.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// fn MyComponent() {
|
||||
/// // ❌ Every time MyComponent runs, it will create a new signal that is only dropped when MyComponent is dropped
|
||||
/// let signal = Signal::new(0);
|
||||
/// use_context_provider(|| signal);
|
||||
/// // ✅ Since the use_context_provider hook only runs when the component is created, the signal will only be created once and it will be dropped when MyComponent is dropped
|
||||
/// let signal = use_context_provider(|| Signal::new(0));
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// </div>
|
||||
#[track_caller]
|
||||
pub fn new(value: T) -> Self {
|
||||
Self::new_maybe_sync(value)
|
||||
@@ -70,16 +62,60 @@ impl<T: 'static> Signal<T> {
|
||||
Self::new_maybe_sync_in_scope(value, owner)
|
||||
}
|
||||
|
||||
/// Creates a new global Signal that can be used in a global static.
|
||||
#[track_caller]
|
||||
/// Creates a new [`GlobalSignal`] that can be used anywhere inside your dioxus app. This signal will automatically be created once per app the first time you use it.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust, no_run
|
||||
/// # use dioxus::prelude::*;
|
||||
/// // Create a new global signal that can be used anywhere in your app
|
||||
/// static SIGNAL: GlobalSignal<i32> = Signal::global(|| 0);
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// onclick: move |_| *SIGNAL.write() += 1,
|
||||
/// "{SIGNAL}"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// Global signals are generally not recommended for use in libraries because it makes it more difficult to allow multiple instances of components you define in your library.
|
||||
///
|
||||
/// </div>
|
||||
pub const fn global(constructor: fn() -> T) -> GlobalSignal<T> {
|
||||
GlobalSignal::new(constructor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + 'static> Signal<T> {
|
||||
/// Creates a new global Signal that can be used in a global static.
|
||||
#[track_caller]
|
||||
/// Creates a new [`GlobalMemo`] that can be used anywhere inside your dioxus app. This memo will automatically be created once per app the first time you use it.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust, no_run
|
||||
/// # use dioxus::prelude::*;
|
||||
/// static SIGNAL: GlobalSignal<i32> = Signal::global(|| 0);
|
||||
/// // Create a new global memo that can be used anywhere in your app
|
||||
/// static DOUBLED: GlobalMemo<i32> = Signal::global_memo(|| SIGNAL() * 2);
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// rsx! {
|
||||
/// button {
|
||||
/// // When SIGNAL changes, the memo will update because the SIGNAL is read inside DOUBLED
|
||||
/// onclick: move |_| *SIGNAL.write() += 1,
|
||||
/// "{DOUBLED}"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// Global memos are generally not recommended for use in libraries because it makes it more difficult to allow multiple instances of components you define in your library.
|
||||
///
|
||||
/// </div>
|
||||
pub const fn global_memo(constructor: fn() -> T) -> GlobalMemo<T> {
|
||||
GlobalMemo::new(constructor)
|
||||
}
|
||||
@@ -116,11 +152,20 @@ impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
|
||||
pub fn new_with_caller(
|
||||
value: T,
|
||||
#[cfg(debug_assertions)] caller: &'static std::panic::Location<'static>,
|
||||
) -> Self {
|
||||
/// Creates a new Signal with an explicit caller. Signals are a Copy state management solution with automatic dependency tracking.
|
||||
///
|
||||
/// This method can be used to provide the correct caller information for signals that are created in closures:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// #[track_caller]
|
||||
/// fn use_my_signal(function: impl FnOnce() -> i32) -> Signal<i32> {
|
||||
/// // We capture the caller information outside of the closure so that it points to the caller of use_my_custom_hook instead of the closure
|
||||
/// let caller = std::panic::Location::caller();
|
||||
/// use_hook(move || Signal::new_with_caller(function(), caller))
|
||||
/// }
|
||||
/// ```
|
||||
pub fn new_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self {
|
||||
Self {
|
||||
inner: CopyValue::new_with_caller(
|
||||
SignalData {
|
||||
|
||||
@@ -6,7 +6,31 @@ use crate::read::Readable;
|
||||
#[allow(type_alias_bounds)]
|
||||
pub type WritableRef<'a, T: Writable, O = <T as Readable>::Target> = T::Mut<'a, O>;
|
||||
|
||||
/// A trait for states that can be read from like [`crate::Signal`], or [`crate::GlobalSignal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API. For example, instead of creating two functions, one that accepts a [`crate::Signal`] and one that accepts a [`crate::GlobalSignal`], you can create one function that accepts a [`Writable`] type.
|
||||
/// A trait for states that can be written to like [`crate::Signal`]. You may choose to accept this trait as a parameter instead of the concrete type to allow for more flexibility in your API.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
/// enum MyEnum {
|
||||
/// String(String),
|
||||
/// Number(i32),
|
||||
/// }
|
||||
///
|
||||
/// fn MyComponent(mut count: Signal<MyEnum>) -> Element {
|
||||
/// rsx!{
|
||||
/// button {
|
||||
/// onclick: move |_| {
|
||||
/// // You can use any methods from the Writable trait on Signals
|
||||
/// match &mut *count.write() {
|
||||
/// MyEnum::String(s) => s.push('a'),
|
||||
/// MyEnum::Number(n) => *n += 1,
|
||||
/// }
|
||||
/// },
|
||||
/// "Add value"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Writable: Readable {
|
||||
/// The type of the reference.
|
||||
type Mut<'a, R: ?Sized + 'static>: DerefMut<Target = R>;
|
||||
@@ -112,7 +136,7 @@ pub trait Writable: Readable {
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait for Writable<Option<T>> that provides some convenience methods.
|
||||
/// An extension trait for [`Writable<Option<T>>`]` that provides some convenience methods.
|
||||
pub trait WritableOptionExt<T: 'static>: Writable<Target = Option<T>> {
|
||||
/// Gets the value out of the Option, or inserts the given value if the Option is empty.
|
||||
#[track_caller]
|
||||
@@ -146,7 +170,7 @@ where
|
||||
{
|
||||
}
|
||||
|
||||
/// An extension trait for Writable<Vec<T>> that provides some convenience methods.
|
||||
/// An extension trait for [`Writable<Vec<T>>`] that provides some convenience methods.
|
||||
pub trait WritableVecExt<T: 'static>: Writable<Target = Vec<T>> {
|
||||
/// Pushes a new value to the end of the vector.
|
||||
#[track_caller]
|
||||
@@ -227,7 +251,7 @@ pub trait WritableVecExt<T: 'static>: Writable<Target = Vec<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the values of a `Writable<Vec<T>>`.
|
||||
/// An iterator over the values of a [`Writable<Vec<T>>`].
|
||||
pub struct WritableValueIterator<'a, R> {
|
||||
index: usize,
|
||||
value: &'a mut R,
|
||||
|
||||
Reference in new issue
Block a user