#Forcing refresh of child components when parents change?

1 messages · Page 1 of 1 (latest)

toxic jackal
#

I want to reset/flush/something a child component whenever the parent changes, but because nothing about the child specifically depends on the parent (and even when I try injecting something just to force that), it seems that the child is completely independent of the parent. I can imagine many scenarios where that is absolutely desirable, so I support that as the default, but I'd like to find a way to override it when needed. An example, modifying the dx new code (as per my usual 😉 ):

#[component]
fn Blog(id: i32) -> Element {
    rsx! {
        "Blog post {id}"

        Comp {
        }

        Link {
            to: Route::Blog {
                id: 1
            },
            "Go to blog 1"
        }

        Link {
            to: Route::Blog {
                id: 2
            },
            "Go to blog 2"
        }
    }
}

#[component]
fn Comp() -> Element {
    // TODO: want this to reset to false every time blog id changes!
    let mut clicked = use_signal(|| false);

    rsx! {
        div {
            onclick: move |_| clicked.set(!clicked()),

            if clicked() {
                "Yes clicked"
            } else {
                "Not clicked"
            }
        }
    }
}

If you click on the Not clicked message on a blog page, such that it goes to Yes clicked, thereafter, clicking back and forth between Go to blog 1 and Go to blog 2 does not reset the clicked signal. Understandable and fine, but I'd like to know how I can force it anyway, whenever the parent blog id has changed.

Thank you!

novel kraken
#

what exactly of the parent changes?

#

the id?

toxic jackal
#

Yes, when you click the links as I described, the blog id is changing

novel kraken
#

I wonder if you could

Comp {
   key: "{id}"
}
toxic jackal
#

No, that panics

#

Wait, the panic was a typo, sorry

#

But still does not fix it

#

I had tried something similar:

Comp {
    id,
}

...
fn Comp(id: ReadOnlySignal<i32>) -> Element {
    // TODO: want this to reset to false every time blog id changes!
    let mut clicked = use_signal(|| false);

    use_effect(move || {
        let id = id();
        clicked.set(false);
    });

But this ends up behaving very strangely, where sometimes it turns off clicked when changing pages and other times it does not.

#

The variant that does work is this:

    let mut old_id = use_signal(|| id());

    use_effect(move || {
        if old_id() != id() {
            clicked.set(false);
            old_id.set(id());
        }
    });

But that seems excessive, and not very flexible, so I was hoping for something like (hypothetically) in the parent to trigger a child refresh or something.

novel kraken
#

You probably want to use use_reactive

calm maple
#
{[rsx!{Comp {
   key: "{id}"
}}].into_iter()}
novel kraken
#

something like this I guess

fn Comp(id: i32) -> Element {
    // TODO: want this to reset to false every time blog id changes!
    let mut clicked = use_signal(|| false);

    use_effect(use_reactive(id, move |id| {
        clicked.set(false);
    }));
novel kraken
toxic jackal
#

In my real world case, I already have a key, as this is a list, but I suppose that means it's even easier, I just concat the parent id and the child id... Will try this

#

Yeah, that totally worked. Thank you!

#

So.... I had 2 cases of this, and I thought they would have the same solution, but it turns out that they are slightly different. I also need to reset a signal within a component whenever an argument changes. Based on the above, I attempted to solve that with the key and iter solution, but it did not. I had also attempted, which did not work:

    use_effect(move || {
        let _ = id();
signal.set(String::new());
    });

How would you recommend I tie 2 signals together such that when one changes, the other resets, but is otherwise independent?

toxic jackal
#

In this case, the id is already a signal, per my code snippet above

#

So use_reactive should be irrelevant, I would think

calm maple
#

use_reactive will memorize the input, reading the signal will subscribe to the input. There is a slight difference between this and reading the id directly:

use_reactive(id(), move |id| {})
calm maple
toxic jackal
#

Hmm, ok, but I tried this:

    use_effect(use_reactive(&id(), move |_| {
        signal.set(String::new());
    }));

And it still is not resetting the signal when id changes

toxic jackal
#

Real demo:

#[component]
fn Blog(id: ReadOnlySignal<i32>) -> Element {
    let mut value = use_signal(|| String::new());

    use_effect(use_reactive(&id(), move |_| {
        value.set(String::new());
    }));

    rsx! {
        "Blog post {id}"

        input {
            value,
            oninput: move |evt: Event<FormData>| value.set(evt.value()),
        }

        Link {
            to: Route::Blog {
                id: 1
            },
            "Go to blog 1"
        }

        Link {
            to: Route::Blog {
                id: 2
            },
            "Go to blog 2"
        }
    }
}

It resets the input text after going to the other blog and then coming back -- but not when going to the other blog to begin with, as is the goal.

toxic jackal
#

Hmmmmm. Extremely unfortunately, the approach I attempted for my real code wroks exactly as desired in my demo:

    use_effect(move || {
        let _ = id();
        value.set(String::new());
    });

That does the trick -- in the demo. In the real thing, it never triggers except on first load of the component...

calm maple
#

What about:

use_memo(move || {
        let _ = id();
        value.set(String::new());
});
toxic jackal
#

Sadly no

toxic jackal
#

I found a work around, but I am slightly suspicious there might be a bug here somewhere, possibly related to passing a readonlysignal through multiple components and then a use_effect on that

#

Because the use_effect that works in the simple demo, literally does not get triggered when it should in the more real case

calm maple
#

Are you on the published or git version of dioxus?

toxic jackal
#

I am on a potentially slightly out of date git version

#

I can try rebasing

toxic jackal
#

I rebased and the use_effect still fails to trigger when I would expect it to in my current setup

#

I switched my demo to also use my local git repo instead of "0.5" and that one still works.

Hopefully, probably, I'm just doing something subtly different in my real code that makes this approach not work. My workaround is satisfying enough for me, and at this point I highlight this unexpected outcome only in case someone else mentions it, to add weight as a possible bug. For now, I'll ignore it.

And thanks again!

#

From the real code:

#[component]
pub fn Comp1(id: ReadOnlySignal<UuidWrapper>) -> Element {
...
    rsx! {
        Comp2 {
            id,
...
        }
    }
}

#[component]
fn Comp2(
    id: ReadOnlySignal<UuidWrapper>,
...
) -> Element {
...
    log::warn!("actual {}", id());

    use_effect(move || {
        let _ = id();
        //signal.set
        log::warn!("effecting");
    });

I see actual ... get logged with different id values, I do not see effecting get logged after the very first load, even when id changes.