Function leptos::create_action

source ·
pub fn create_action<I, O, F, Fu>(action_fn: F) -> Action<I, O>
where I: 'static, O: 'static, F: Fn(&I) -> Fu + 'static, Fu: Future<Output = O> + 'static,
Expand description

Creates an Action to synchronize an imperative async call to the synchronous reactive system.

If you’re trying to load data by running an async function reactively, you probably want to use a create_resource instead. If you’re trying to occasionally run an async function in response to something like a user clicking a button, you’re in the right place.

async fn send_new_todo_to_api(task: String) -> usize {
    // do something...
    // return a task id
    42
}
let save_data = create_action(|task: &String| {
  // `task` is given as `&String` because its value is available in `input`
  send_new_todo_to_api(task.clone())
});

// the argument currently running
let input = save_data.input();
// the most recent returned result
let result_of_call = save_data.value();
// whether the call is pending
let pending = save_data.pending();
// how many times the action has run
// useful for reactively updating something else in response to a `dispatch` and response
let version = save_data.version();

// before we do anything
assert_eq!(input.get(), None); // no argument yet
assert_eq!(pending.get(), false); // isn't pending a response
assert_eq!(result_of_call.get(), None); // there's no "last value"
assert_eq!(version.get(), 0);
// dispatch the action
save_data.dispatch("My todo".to_string());

// when we're making the call
// assert_eq!(input.get(), Some("My todo".to_string()));
// assert_eq!(pending.get(), true); // is pending
// assert_eq!(result_of_call.get(), None); // has not yet gotten a response

// after call has resolved
assert_eq!(input.get(), None); // input clears out after resolved
assert_eq!(pending.get(), false); // no longer pending
assert_eq!(result_of_call.get(), Some(42));
assert_eq!(version.get(), 1);

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 Action::input as well.

// if there's a single argument, just use that
let action1 = create_action(|input: &String| {
    let input = input.clone();
    async move { todo!() }
});

// if there are no arguments, use the unit type `()`
let action2 = create_action(|input: &()| async { todo!() });

// if there are multiple arguments, use a tuple
let action3 = create_action(|input: &(usize, String)| async { todo!() });