Skip to content

Clarify the lifetime of values created in Bounc, especially InputSelector and Query #94

Open
@zstewar1

Description

@zstewar1

It would be helpful if the Book and API docs would make it clear how long state values created by Bounce live for.

I assume for basic Atoms, once you use them once they live for the full lifetime of the BounceRoot (is that true though?), which is why I want to focus on InputSelector and Query which are slightly less clear.

The documentation says that input selectors and queries are recalculated if the input changes, but the documentation for input selector also says "Each selector with a different input are treated as a different selector.", which sounds like InputSelector are keyed on values not just on types.

What happens when you change the input for an InputSelector or Query hook? Is the old value of the selector/query dropped? How does that work if I have two different components using the same InputSelector/Query but with different inputs?

My biggest concern is that I don't want to create a memory leak by repeatedly changing the input value for an InputSelector or Query and having the BounceRoot accumulate a massive cache of values with other old inputs just in case I use them again, though it would also be helpful to understand how InputSelector and Query work when there are different components sending different inputs, since I also wouldn't want to have the value repeatedly recalculated due to different components sending different inputs.

Examples:

#[derive(Properties, PartialEq)]
struct Props {
    user_id: Rc<u64>,
}

#[function_component]
fn GreetUser(props: &Props) -> Html {
    let user = use_query_value::<UserQuery>(props.user_id.clone());

    match user.result() {
        // The result is None if the query is currently loading.
        None => html! {<div>{"loading..."}</div>},
        // The result is Some(Ok(_)) if the query has loaded successfully.
        Some(Ok(m)) => html! {<div>{"User's name is "}{m.value.name.to_string()}</div>},
        // The result is Some(Err(_)) if an error is returned during fetching.
        Some(Err(e)) => html! {<div>{"Oops, something went wrong."}</div>},
    }
}

// Suppose I have an input that selects between different user_id values and pass them 
// down to the `GreetUser` component.
#[function_component]
fn UserSelection() -> Html {
    let selected_user = use_state(|| 0);
    // Every time this on-click fires, we will re-render `GreetUser` with a new input prop 
    // for `user_id`, which will then be passed to `use_query_value`. 
    //
    // What will happen to the old `User` value from the `UserQuery` after each
    // increment? Will it stay cached in the `BounceRoot` or will it get dropped?
    let onclick = {
        let selected_user = selected_user.clone();
        Callback::from(move |_| selected_user.set(*selected_user + 1))
    };

    html! {
        <div>
            <button {onclick}>{ "Next User" }</button>
            <GreetUser user_id={Rc::new(*selected_user)} />
        </div>
    }
}

// Suppose I try to run the same query with multiple different inputs at the same time:
html! {
    <div>
        // I assume this will "just work" and each greeter will run its query independently,
        // but it would be good if the documentation was more explicit about how inputs
        // to `InputSelector` and `Query` interact with their caching.
        <GreetUser user_id={Rc::new(0)} />
        <GreetUser user_id={Rc::new(1)} />
    </div>
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions