-
First of all, I must say that this project is really out of my expectations, looking forward to a greater leptos-ecosystem! #[derive(Clone)]
enum State {
Lobby { player_count: u32, ready: bool },
InGame { card_count: u32, countdown: u32 },
}
#[component]
fn GameView(state: Signal<State>) -> impl IntoView {
move || match state.get() {
State::Lobby {
player_count,
ready,
} => view! {
<span>"player: "{player_count}</span>
<span>"ready: "{ready}</span>
}
.into_view(),
State::InGame {
card_count,
countdown,
} => view! {
<span>"cards: "{card_count}</span>
<span>"countdown: "{countdown}</span>
}
.into_view(),
}
} Now this approach works, but it would trigger a rerender each time the state changes. A common scenario is that only part of the enum is changed, and ideally only the number should change, but I couldn't think of a better way to implement this due to the need of a |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
I just want to start by acknowledging that there are pain points with this kind of scenario and fine-grained reactivity, so don't feel like you're doing anything wrong if it's a little painful. Signals work really well when your local interactions are what's driving state, but relatively less well with a big glob of global state, especially when it comes from an external source. That said, it's achievable. I'd recommend a memo that just toggles back and forth between the two modes: #[component]
fn GameView(state: Signal<State>) -> impl IntoView {
let in_game = create_memo(move |_| matches!(state.get(), State::InGame { .. });
move || if in_game.get() {
// show game
} else {
// show lobby
}
} The useful thing about a memo here is that it will only notify/cause a rerender when it actually changes, not every time anything in the In fact the built-in Then you can do fine-grained updates on each field. You can either do this inline in the view, or pull them out into separate derived signals. These do need to check the enum state again unfortunately. #[component]
fn GameView(state: Signal<State>) -> impl IntoView {
let in_game = create_memo(move |_| matches!(state.get(), State::InGame { .. });
let card_count = move || match state.get() {
State::InGame { card_count, .. } => card_count,
_ => 0
};
let countdown = move || match state.get() {
State::InGame { countdown, .. } => countdown,
_ => 0 // or some default
};
// etc.
move || if in_game.get() {
view! {
<span>"cards: " {card_count}</span>
<span>"countdown: " {countdown}</span>
}
} else {
// same for lobby
}
} So, deriving fine-grained signals from an external state source like this is somewhat painful but the alternative is a VDOM which diffs at the component level, which is not what Leptos does right now. You can use |
Beta Was this translation helpful? Give feedback.
I just want to start by acknowledging that there are pain points with this kind of scenario and fine-grained reactivity, so don't feel like you're doing anything wrong if it's a little painful. Signals work really well when your local interactions are what's driving state, but relatively less well with a big glob of global state, especially when it comes from an external source.
That said, it's achievable.
I'd recommend a memo that just toggles back and forth between the two modes: