Loading initial value from server in Leptos

44 Views Asked by At

I'm building an app in Leptos where I want the UI to load an initial value from the server (from the database), but then I want to be able to update that value in the UI and send the new value back.

I can easily create a client side-only value like so:

#[component]
fn HomePage() -> impl IntoView {
    let puzzle_text = create_rw_signal("".to_string());

    let save_puzzle = create_action(|input: &String| {
        let input = input.clone();
        async move {
            set_puzzle(1, input).await  // <-- server function
        }
    });

    view! {
        <h1>"Here's the puzzle!"</h1>
        <input type="text"
            on:input=move |ev| { puzzle_text.set(event_target_value(&ev)) }
            prop:value=puzzle_text
        />
        <button on:click=move |_| {
            save_puzzle.dispatch(puzzle_text.get());
        }>"Save Puzzle"</button>
    }
}

Or I can create a resource to fetch the value from the backend:

#[component]
fn HomePage() -> impl IntoView {
    let initial_puzzle_text = create_resource(
        || (),
        |_| async move {
            get_puzzle(1).await.unwrap_or("".to_string())
        }
    );

    let save_puzzle = create_action(...);

    view! {
        <h1>"Here's the puzzle!"</h1>
        <Suspense fallback=move || view! { <p>"Loading"</p> }>
            {move || {
                initial_puzzle_text.get().map(|p| view! {
                    <input type="text"
                        prop:value=p.clone()
                    />
                    <button on:click=move |_| {
                        save_puzzle.dispatch(p.clone());  // <-- doesn't update with <input/>
                    }>"Save Puzzle"</button>
                })
            }}
        </Suspense>
    }
}

But I can't figure out how to enable both reading the initial value from the backend and writing that value back to the backend. I feel like I'm missing something simple with RW signals.

I have tried setting the RW signal from within the resource, like so:

let puzzle_text = create_rw_signal("A".to_string());

let initial_puzzle_text = create_resource(
    || (),
    |_| async move {
        puzzle_text.set(get_puzzle(1).await.unwrap_or("B".to_string()));
    }
);

but while I see the request hit the backend (I see a SELECT SQL statement execute and return a result, and logging within the resource's closure works), the value of the RW signal never gets set and it keeps its initial value.

1

There are 1 best solutions below

0
On

Easiest answer I've found so far: use a RW signal and make initialization an action:

let load_puzzle = create_action(move |_: &()| {
    async move {
        puzzle_text.set(get_puzzle(1).await.unwrap_or("".to_string()));
    }
});

load_puzzle.dispatch(());