pub struct MultiAction<I, O, S = SyncStorage> { /* private fields */ }Expand description
An action that synchronizes multiple imperative async calls to the reactive system,
tracking the progress of each one.
Where an Action fires a single call, a MultiAction allows you to
keep track of multiple in-flight actions.
If you’re trying to load data by running an async function reactively, you probably
want to use an AsyncDerived instead.
If you’re trying to occasionally run an async function in response to something
like a user adding a task to a todo list, you’re in the right place.
The reference-counted, Clone (but not Copy version of a MultiAction is an ArcMultiAction.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let add_todo = MultiAction::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
add_todo.dispatch("Buy milk".to_string());
add_todo.dispatch("???".to_string());
add_todo.dispatch("Profit!!!".to_string());
let submissions = add_todo.submissions();
assert_eq!(submissions.with(Vec::len), 3);Implementations§
Source§impl<I, O> MultiAction<I, O>
impl<I, O> MultiAction<I, O>
Sourcepub fn new<Fut>(
action_fn: impl Fn(&I) -> Fut + Send + Sync + 'static,
) -> MultiAction<I, O>
pub fn new<Fut>( action_fn: impl Fn(&I) -> Fut + Send + Sync + 'static, ) -> MultiAction<I, O>
Creates a new multi-action.
The input to the async function should always be a single value,
but it can be of any type. The argument is always passed by reference to the
function, because it is stored in Submission::input as well.
// if there's a single argument, just use that
let action1 = MultiAction::new(|input: &String| {
let input = input.clone();
async move { todo!() }
});
// if there are no arguments, use the unit type `()`
let action2 = MultiAction::new(|input: &()| async { todo!() });
// if there are multiple arguments, use a tuple
let action3 =
MultiAction::new(|input: &(usize, String)| async { todo!() });Source§impl<I, O, S> MultiAction<I, O, S>
impl<I, O, S> MultiAction<I, O, S>
Sourcepub fn dispatch(&self, input: I)
pub fn dispatch(&self, input: I)
Calls the async function with a reference to the input type as its argument.
This can be called any number of times: each submission will be dispatched, running
concurrently, and its status can be checked via the
submissions() signal.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let add_todo = MultiAction::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
let submissions = add_todo.submissions();
let pending_submissions = move || {
submissions.with(|subs| subs.iter().filter(|sub| sub.pending().get()).count())
};
add_todo.dispatch("Buy milk".to_string());
assert_eq!(submissions.with(Vec::len), 1);
assert_eq!(pending_submissions(), 1);
add_todo.dispatch("???".to_string());
add_todo.dispatch("Profit!!!".to_string());
assert_eq!(submissions.with(Vec::len), 3);
assert_eq!(pending_submissions(), 3);
// when submissions resolve, they are not removed from the set
// however, their `pending` signal is now `false`, and this can be used to filter them
assert_eq!(submissions.with(Vec::len), 3);
assert_eq!(pending_submissions(), 0);Sourcepub fn dispatch_sync(&self, value: O)
pub fn dispatch_sync(&self, value: O)
Synchronously adds a submission with the given value.
This takes the output value, rather than the input, because it is adding a result, not an input.
This can be useful for use cases like handling errors, where the error can already be known on the client side.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let add_todo = MultiAction::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
let submissions = add_todo.submissions();
let pending_submissions = move || {
submissions.with(|subs| subs.iter().filter(|sub| sub.pending().get()).count())
};
add_todo.dispatch("Buy milk".to_string());
assert_eq!(submissions.with(Vec::len), 1);
assert_eq!(pending_submissions(), 1);
add_todo.dispatch_sync(42);
assert_eq!(submissions.with(Vec::len), 2);
assert_eq!(pending_submissions(), 1);Source§impl<I, O> MultiAction<I, O>
impl<I, O> MultiAction<I, O>
Sourcepub fn submissions(&self) -> ReadSignal<Vec<ArcSubmission<I, O>>>
pub fn submissions(&self) -> ReadSignal<Vec<ArcSubmission<I, O>>>
The set of all submissions to this multi-action.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let add_todo = MultiAction::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
let submissions = add_todo.submissions();
add_todo.dispatch("Buy milk".to_string());
add_todo.dispatch("???".to_string());
add_todo.dispatch("Profit!!!".to_string());
assert_eq!(submissions.with(Vec::len), 3);Source§impl<I, O, S> MultiAction<I, O, S>where
I: 'static,
O: 'static,
S: Storage<ArcMultiAction<I, O>> + Storage<ArcReadSignal<Vec<ArcSubmission<I, O>>>>,
impl<I, O, S> MultiAction<I, O, S>where
I: 'static,
O: 'static,
S: Storage<ArcMultiAction<I, O>> + Storage<ArcReadSignal<Vec<ArcSubmission<I, O>>>>,
Sourcepub fn version(&self) -> RwSignal<usize>
pub fn version(&self) -> RwSignal<usize>
How many times an action has successfully resolved.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let add_todo = MultiAction::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
let version = add_todo.version();
add_todo.dispatch("Buy milk".to_string());
add_todo.dispatch("???".to_string());
add_todo.dispatch("Profit!!!".to_string());
assert_eq!(version.get(), 0);
// when they've all resolved
assert_eq!(version.get(), 3);Trait Implementations§
Source§impl<I, O, S> Clone for MultiAction<I, O, S>where
I: 'static,
O: 'static,
impl<I, O, S> Clone for MultiAction<I, O, S>where
I: 'static,
O: 'static,
Source§fn clone(&self) -> MultiAction<I, O, S>
fn clone(&self) -> MultiAction<I, O, S>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<I, O, S> DefinedAt for MultiAction<I, O, S>where
I: 'static,
O: 'static,
impl<I, O, S> DefinedAt for MultiAction<I, O, S>where
I: 'static,
O: 'static,
Source§fn defined_at(&self) -> Option<&'static Location<'static>>
fn defined_at(&self) -> Option<&'static Location<'static>>
None in
release mode.Source§impl<I, O, S> Dispose for MultiAction<I, O, S>
impl<I, O, S> Dispose for MultiAction<I, O, S>
Source§impl<S> From<ServerMultiAction<S>> for MultiAction<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
impl<S> From<ServerMultiAction<S>> for MultiAction<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
Source§fn from(
value: ServerMultiAction<S>,
) -> MultiAction<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
fn from( value: ServerMultiAction<S>, ) -> MultiAction<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
impl<I, O, S> Copy for MultiAction<I, O, S>where
I: 'static,
O: 'static,
Auto Trait Implementations§
impl<I, O, S> Freeze for MultiAction<I, O, S>
impl<I, O, S> RefUnwindSafe for MultiAction<I, O, S>
impl<I, O, S> Send for MultiAction<I, O, S>
impl<I, O, S> Sync for MultiAction<I, O, S>
impl<I, O, S> Unpin for MultiAction<I, O, S>
impl<I, O, S> UnwindSafe for MultiAction<I, O, S>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more