Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected behavior of reactivity in Indexed and Keyed #781

Open
AMNRG opened this issue Jan 15, 2025 · 0 comments
Open

Unexpected behavior of reactivity in Indexed and Keyed #781

AMNRG opened this issue Jan 15, 2025 · 0 comments
Labels
A-reactivity Area: reactivity and state handling C-bug Category: bug, something isn't working S-needs-mre Needs a MRE (Minimal Reproducible Example)

Comments

@AMNRG
Copy link
Contributor

AMNRG commented Jan 15, 2025

Describe the bug
I was trying to implement a simple paginator, but I keep getting error closure invoked recursively or after being dropped and the currently selected element is not correctly updated. The problem seems to occur only with elements '1', '2' and '8', '9', which are not initially visible.
Replacing props.current_page.get() with props.current_page.get_untracked() prevents the problem with the error, but also does not update the current element.
Swapping Indexed with Keyed+key=|page| *page, is even worse.

To Reproduce

use sycamore::prelude::*;

#[component]
fn App() -> View {
    let current_page = create_signal(5);
    let total_pages = create_signal(9);

    view! {
        Paginator(
            current_page=current_page,
            total_pages=*total_pages,
        )
    }
}

#[derive(Props)]
pub struct PaginatorProperties {
    pub current_page: Signal<i32>,
    pub total_pages: ReadSignal<i32>,
    #[prop(default=5)]
    pub max_pages: i32,
}

#[component]
fn Paginator(props: PaginatorProperties) -> View {
    let pages = create_memo(move || {
        let current_page = props.current_page.get();
        let total_pages = props.total_pages.get();
        let half_max_pages = props.max_pages / 2;
        let start_page = current_page - half_max_pages;
        let end_page = current_page + half_max_pages;
        let range = if start_page <= 0 {
            1..=props.max_pages.min(total_pages)
        } else if end_page >= total_pages {
            total_pages.saturating_sub(props.max_pages - 1)..=total_pages
        } else {
            start_page..=end_page
        };
        range.collect::<Vec<_>>()
    });

    view! {
        div {
            div { (format!("Current page: {:?}", props.current_page.get())) }
            div { (format!("Pages: {:?}", pages.get_clone())) }
            div {
                Indexed(
                    list=pages,
                    view=move |page| view! {
                        (if page == props.current_page.get() {
                            view! { CurrentPageButton(page=page) }
                        } else {
                            view! { PageButton(current_page=props.current_page, page=page) }
                        })
                    },
                )
            }
        }
    }
}

#[component(inline_props)]
fn CurrentPageButton(page: i32) -> View {
    view! {
        span(style="background-color: green; padding: 2px 4px") { (page.to_string()) }
    }
}

#[component(inline_props)]
fn PageButton(current_page: Signal<i32>, page: i32) -> View {
    view! {
        button(r#type="button", on:click=move |_| current_page.set(page)) { (page.to_string()) }
    }
}

fn main() {
    console_error_panic_hook::set_once();
    sycamore::render(App);
}
  1. Click '7'
  2. Click '9' (=> '7' does not become a 'PageButton' and '9' does not become 'CurrentPageButton')
  3. Click '8' (=> closure invoked recursively or after being dropped)

Expected behavior
No errors. Reactivity should also be given within Indexed & Keyed.

Screenshots
image

Environment

  • Sycamore: main
@lukechu10 lukechu10 added C-bug Category: bug, something isn't working A-reactivity Area: reactivity and state handling S-needs-mre Needs a MRE (Minimal Reproducible Example) labels Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-reactivity Area: reactivity and state handling C-bug Category: bug, something isn't working S-needs-mre Needs a MRE (Minimal Reproducible Example)
Projects
None yet
Development

No branches or pull requests

2 participants