Leptos Query

Crates.io

Leptos Query is a asynchronous state management library for Leptos.

Heavily inspired by Tanstack Query.

Queries are useful for data fetching, caching, and synchronization with server state.

A Query provides:

Installation

bash cargo add leptos_query --optional

Then add the relevant feature(s) to your Cargo.toml

... meaning the rest of the dependencies you may have.

```toml

[features] hydrate = [ "leptosquery/hydrate", # ... ] ssr = [ "leptosquery/ssr", # ... ]

```

Quick Start

In the root of your App, provide a query client:

```rust use leptos_query::; use leptos::;

[component]

pub fn App(cx: Scope) -> impl IntoView { // Provides Query Client for entire app. providequeryclient(cx);

// Rest of App...

} ```

Then make a query function.

NOTE:

TLDR: Wrap your key in a Newtype when needed to ensure uniqueness.

```rust

// Create a Newtype for MonkeyId. #[derive(Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] struct MonkeyId(String);

// Monkey fetcher. async fn get_monkey(id: MonkeyId) -> Monkey { todo!() }

// Query for a Monkey. fn usemonkeyquery(cx: Scope, id: impl Fn() -> MonkeyId + 'static) -> QueryResult { leptosquery::usequery( cx, id, getmonkey, QueryOptions { defaultvalue: None, refetchinterval: None, resourceoption: ResourceOption::NonBlocking, // Considered stale after 5 seconds. staletime: Some(Duration::fromsecs(5)), // Infinite cache time. cache_time: None, }, ) }

```

Now you can use the query in any component in your app.

```rust

[component]

fn MonkeyView(cx: Scope, id: MonkeyId) -> impl IntoView { let query = usemonkeyquery(cx, move || id.clone()); let QueryResult { data, isloading, isfetching, is_stale .. } = query;

view! { cx,
  // You can use the query result data here.
  // Everything is reactive.
   <div>
       <div>
           <span>"Loading Status: "</span>
           <span>{move || { if is_loading.get() { "Loading..." } else { "Loaded" } }}</span>
       </div>
       <div>
           <span>"Fetching Status: "</span>
           <span>
               {move || { if is_fetching.get() { "Fetching..." } else { "Idle" } }}
           </span>
       </div>
       <div>
           <span>"Stale Status: "</span>
           <span>
               {move || { if is_stale.get() { "Stale" } else { "Fresh" } }}
           </span>
       </div>
       // Query data should be read inside a Transition/Suspense component.
       <Transition
           fallback=move || {
               view! { cx, <h2>"Loading..."</h2> }
           }>
           {move || {
               data()
                   .map(|monkey| {
                       view! { cx, <h2>{monkey.name}</h2> }
                   })
           }}
       </Transition>
   </div>
}

}

```

For a complete working example see the example directory

FAQ

How's this different from a leptos Resource?

A Query uses a resource under the hood, but provides additional functionality like caching, de-duplication, and invalidation.

Resources are individually bound to the Scope they are created in.

Queries are all bound to the QueryClient they are created in.

Meaning, once you have a QueryClient in your app, you can access the value for a query anywhere in your app.

With a resource, you have to manually lift it to a higher scope if you want to preserve it. And this can be cumbersome if you have a many resources.

What is the difference between stale_time and cache_time?

staleTime is the duration until a query transitions from fresh to stale. As long as the query is fresh, data will always be read from the cache only.

When a query is stale, it will be refetched on its next usage.

cacheTime is the duration until inactive queries will be removed from cache.

These can be configured per-query using QueryOptions

If you want infinite cache/stale time, you can set stale_time and cache_time to None.