mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: with!
macros (#1693)
This commit is contained in:
parent
a317874f93
commit
00f8c9583d
3 changed files with 217 additions and 19 deletions
|
@ -65,6 +65,34 @@ if names.with(Vec::is_empty) {
|
|||
|
||||
After all, `.with()` simply takes a function that takes the value by reference. Since `Vec::is_empty` takes `&self`, we can pass it in directly and avoid the unnecessary closure.
|
||||
|
||||
There are some helper macros to make using `.with()` and `.update()` easier to use, especially when using multiple signals.
|
||||
|
||||
```rust
|
||||
let (first, _) = create_signal("Bob".to_string());
|
||||
let (middle, _) = create_signal("J.".to_string());
|
||||
let (last, _) = create_signal("Smith".to_string());
|
||||
```
|
||||
|
||||
If you wanted to concatenate these 3 signals together without unnecessary cloning, you would have to write something like:
|
||||
|
||||
```rust
|
||||
let name = move || {
|
||||
first.with(|first| {
|
||||
middle.with(|middle| last.with(|last| format!("{first} {middle} {last}")))
|
||||
})
|
||||
};
|
||||
```
|
||||
|
||||
Which is very long and annoying to write.
|
||||
|
||||
Instead, you can use the `with!` macro to get references to all the signals at the same time.
|
||||
|
||||
```rust
|
||||
let name = move || with!(|first, middle, last| format!("{first} {middle} {last}"));
|
||||
```
|
||||
|
||||
This expands to the same thing as above. Take a look at the `with!` docs for more info, and the corresponding macros `update!`, `with_value!` and `update_value!`.
|
||||
|
||||
## Making signals depend on each other
|
||||
|
||||
Often people ask about situations in which some signal needs to change based on some other signal’s value. There are three good ways to do this, and one that’s less than ideal but okay under controlled circumstances.
|
||||
|
|
|
@ -83,6 +83,7 @@ mod context;
|
|||
mod diagnostics;
|
||||
mod effect;
|
||||
mod hydration;
|
||||
mod macros;
|
||||
mod memo;
|
||||
mod node;
|
||||
pub mod oco;
|
||||
|
@ -129,25 +130,6 @@ pub use suspense::{GlobalSuspenseContext, SuspenseContext};
|
|||
pub use trigger::*;
|
||||
pub use watch::*;
|
||||
|
||||
mod macros {
|
||||
macro_rules! debug_warn {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
($crate::console_warn(&format_args!($($x)*).to_string()))
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
($($x)*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use debug_warn;
|
||||
}
|
||||
|
||||
pub(crate) fn console_warn(s: &str) {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", any(feature = "csr", feature = "hydrate")))] {
|
||||
|
|
188
leptos_reactive/src/macros.rs
Normal file
188
leptos_reactive/src/macros.rs
Normal file
|
@ -0,0 +1,188 @@
|
|||
macro_rules! debug_warn {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
($crate::console_warn(&format_args!($($x)*).to_string()))
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
($($x)*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use debug_warn;
|
||||
|
||||
/// Provides a simpler way to use [`SignalWith::with`](crate::SignalWith::with).
|
||||
///
|
||||
/// To use with [stored values](crate::StoredValue), see the [`with_value`](crate::with_value)
|
||||
/// macro instead.
|
||||
///
|
||||
/// The general syntax looks like:
|
||||
/// ```ignore
|
||||
/// with!(|capture1, capture2, ...| body);
|
||||
/// ```
|
||||
/// The variables within the 'closure' arguments are captured from the
|
||||
/// environment, and can be used within the body with the same name.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let (first, _) = create_signal("Bob".to_string());
|
||||
/// let (middle, _) = create_signal("J.".to_string());
|
||||
/// let (last, _) = create_signal("Smith".to_string());
|
||||
/// let name =
|
||||
/// with!(|first, middle, last| { format!("{first} {middle} {last}") });
|
||||
/// assert_eq!(name, "Bob J. Smith");
|
||||
/// # };
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
/// The `with!` macro in the above example expands to:
|
||||
/// ```ignore
|
||||
/// first.with(|first| {
|
||||
/// middle.with(|middle| {
|
||||
/// last.with(|last| format!("{first} {middle} {last}"))
|
||||
/// })
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! with {
|
||||
(|$ident:ident $(,)?| $body:expr) => {
|
||||
$ident.with(|$ident| $body)
|
||||
};
|
||||
(|$first:ident, $($rest:ident),+ $(,)? | $body:expr) => {
|
||||
$first.with(|$first| with!(|$($rest),+| $body))
|
||||
};
|
||||
}
|
||||
|
||||
/// Provides a simpler way to use
|
||||
/// [`StoredValue::with_value`](crate::StoredValue::with_value).
|
||||
///
|
||||
/// To use with [signals](crate::SignalWith::with), see the [`with!`] macro
|
||||
/// instead.
|
||||
///
|
||||
/// The general syntax looks like:
|
||||
/// ```ignore
|
||||
/// with_value!(|capture1, capture2, ...| body);
|
||||
/// ```
|
||||
/// The variables within the 'closure' arguments are captured from the
|
||||
/// environment, and can be used within the body with the same name.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let first = store_value("Bob".to_string());
|
||||
/// let middle = store_value("J.".to_string());
|
||||
/// let last = store_value("Smith".to_string());
|
||||
/// let name = with_value!(|first, middle, last| {
|
||||
/// format!("{first} {middle} {last}")
|
||||
/// });
|
||||
/// assert_eq!(name, "Bob J. Smith");
|
||||
/// # };
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
/// The `with_value!` macro in the above example expands to:
|
||||
/// ```ignore
|
||||
/// first.with_value(|first| {
|
||||
/// middle.with_value(|middle| {
|
||||
/// last.with_value(|last| format!("{first} {middle} {last}"))
|
||||
/// })
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! with_value {
|
||||
(|$ident:ident $(,)?| $body:expr) => {
|
||||
$ident.with_value(|$ident| $body)
|
||||
};
|
||||
(|$first:ident, $($rest:ident),+ $(,)? | $body:expr) => {
|
||||
$first.with_value(|$first| with_value!(|$($rest),+| $body))
|
||||
};
|
||||
}
|
||||
|
||||
/// Provides a simpler way to use
|
||||
/// [`SignalUpdate::update`](crate::SignalUpdate::update).
|
||||
///
|
||||
/// To use with [stored values](crate::StoredValue), see the [`update_value`](crate::update_value)
|
||||
/// macro instead.
|
||||
///
|
||||
/// The general syntax looks like:
|
||||
/// ```ignore
|
||||
/// update!(|capture1, capture2, ...| body);
|
||||
/// ```
|
||||
/// The variables within the 'closure' arguments are captured from the
|
||||
/// environment, and can be used within the body with the same name.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let a = create_rw_signal(1);
|
||||
/// let b = create_rw_signal(2);
|
||||
/// update!(|a, b| *a = *a + *b);
|
||||
/// assert_eq!(a.get(), 3);
|
||||
/// # };
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
/// The `update!` macro in the above example expands to:
|
||||
/// ```ignore
|
||||
/// a.update(|a| {
|
||||
/// b.update(|b| *a = *a + *b)
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! update {
|
||||
(|$ident:ident $(,)?| $body:expr) => {
|
||||
$ident.update(|$ident| $body)
|
||||
};
|
||||
(|$first:ident, $($rest:ident),+ $(,)? | $body:expr) => {
|
||||
$first.update(|$first| update!(|$($rest),+| $body))
|
||||
};
|
||||
}
|
||||
|
||||
/// Provides a simpler way to use
|
||||
/// [`StoredValue::update_value`](crate::StoredValue::update_value).
|
||||
///
|
||||
/// To use with [signals](crate::SignalUpdate::update), see the [`update`]
|
||||
/// macro instead.
|
||||
///
|
||||
/// The general syntax looks like:
|
||||
/// ```ignore
|
||||
/// update_value!(|capture1, capture2, ...| body);
|
||||
/// ```
|
||||
/// The variables within the 'closure' arguments are captured from the
|
||||
/// environment, and can be used within the body with the same name.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use leptos::*;
|
||||
/// # let runtime = create_runtime();
|
||||
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
|
||||
/// let a = store_value(1);
|
||||
/// let b = store_value(2);
|
||||
/// update_value!(|a, b| *a = *a + *b);
|
||||
/// assert_eq!(a.get_value(), 3);
|
||||
/// # };
|
||||
/// # runtime.dispose();
|
||||
/// ```
|
||||
/// The `update_value!` macro in the above example expands to:
|
||||
/// ```ignore
|
||||
/// a.update_value(|a| {
|
||||
/// b.update_value(|b| *a = *a + *b)
|
||||
/// })
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! update_value {
|
||||
(|$ident:ident $(,)?| $body:expr) => {
|
||||
$ident.update_value(|$ident| $body)
|
||||
};
|
||||
(|$first:ident, $($rest:ident),+ $(,)? | $body:expr) => {
|
||||
$first.update_value(|$first| update_value!(|$($rest),+| $body))
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue