-
-
Notifications
You must be signed in to change notification settings - Fork 729
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
Replace get()
with try_get()
in several trait implementations for signals
#3569
Replace get()
with try_get()
in several trait implementations for signals
#3569
Conversation
…arena` macro) to prevent panicking if the signal was disposed
… macro) to prevent panicking if the signal was disposed
…if the signal was disposed
…if the signal was disposed
…or signals to prevent panicking if the signal was disposed
…Effect::new_with_value`
…king if the signal was disposed
Copied from the other one you've opened, so apologies if you read that one first. Feel free to reply to either one Overall I think using .try_get() is a decent solution here for panic prevention, but I am worried that instead of getting a panic it seems like this implementation just eats the error. I imagine it would have to emit an error somewhere user visible, whether that's the console in the browser or the server log on the server when the Signal is disposed. I'm not sure returning the previous value is a good choice there either |
Sorry for the duplicated commit history. I wrote (#3582) based on the changes here. Although this PR includes some newer commits not present in the later PR. Generally, I think if you merge this one first and then the later one, commits with the same hashes will be unified. Most of the time, disposed signals occur when a reactive item is deleted. (For example, deleting an |
Yeah, that sounds reasonable to me |
I added a macro called I'm unsure about:
I've pushed the changes for now to get some help here. In |
Overall I like it, although I'd definitely want @gbj to review it as this is definitely his domain. The error message itself should probably match whatever we show in the browser console, which my github-fu has somehow failed to find. I appreciate you taking the time to make the PR! |
Thanks. Yes, especially now that there's a conflict with PR #3618. |
I was thinking about a new implementation that uses a concrete type to address the limitations of trait specialization. This way, the numerous macro rules currently written could be replaced with an implementation that returns the concrete type. I don’t yet have a clear path to write it, but I think it’s similar to what’s already done in |
A couple comments:
It seems clear that you've encountered an issue with signals panicking in the renderer in some scenario but I am not clear on what that is, and I wonder whether addressing the root cause of that issue may be productive. Could you provide an example that currently panics when it shouldn't? |
Thanks for checking. What I’m aiming for is a way to handle this internally by using I’ll admit the current implementation feels a bit verbose. I tried to reproduce something like Bind. I implemented the InnerHtmlValue like this: impl<T, V> InnerHtmlValue for T
where
T: Into<Signal<V>> + Send,
V: InnerHtmlValue + Clone + Send + Sync + 'static,
V::State: 'static, But the compiler said there is conflict with other implementations which I guess you've experienced it before. And about branching, sure if you generally agree with current direction I’ll try rewriting it in the 0.8 branch. |
Hm... But I think my question continues to be: Do you have an example where the application is written correctly but you need to do this? I think that's what I'm looking for in order to understand it. I can understand occasional edge cases where you might want to dispose of a signal early and need to use |
To clarify, remember that thread in Discord where we discussed this, and you shared a working example? Here’s the link: I tweaked it a bit. I created a separate struct for session items and then used the selected session’s fields reactively in a <strong>
"Selected Item: "
{move || {
selected_session
.try_get()
.flatten()
.map(|item| {
view! { {move || item.field1().get()} }
})
}}
</strong> So, creating a separate |
As I understand it, the issue in the example you linked comes when you select and then delete an item, right? I think this is because you remove the item from the list before the clear the selected item, so there's a moment when the item no longer exists but the "Selected Item: " display still expects it to be there. // after this, the session no longer exists
state.sessions().write().remove(removing_index);
// and we un-select it
if is_same_session {
selected_session.set(None);
} I tried simply inverting the order of these, so it cleared the "selected item" before deleting the item, and it no longer panics: if is_same_session {
selected_session.set(None);
}
state.sessions().write().remove(removing_index); Editing to add: this one below does not need to be a {move || {
selected_session
.get()
.map(|item| {
view! { {move || item.field1().get()} }
})
}} |
Thanks. My mistake. I made the changes. if is_same_session {
selected_session.set(state.sessions().into_iter().next().map(Into::into));
} And I have a class for each item, which reactively changes depending on whether it's selected. class:selected=move || {
selected_session
.read()
.is_some_and(|item| { *item.field0().read() == *session.field0().read() })
} With this changes the error appears again because it uses the selected_session in the class attribute. |
I checked out the PR branch and your updated example in the PR still panics, though, with the exact same panic message as on I have to log off for the next nine hours or so. I just want to make sure it's clear: I appreciate the work you've done, and I'm not trying to dismiss it, I'm just trying to understand if there are specific cases this PR addresses where 1) the code is written correctly/can't be rewritten to work, and 2) the PR fixes the issue. |
Oh, my mistake again! I forgot that I used class:selected=move || {
selected_session
.read()
.is_some_and(|item| {
item.field0().try_read().as_deref().as_ref() // here
== session.field0().try_read().as_deref().as_ref() // here
})
} And no errors! |
try_get()
with get()
in several trait implementations for signalsget()
with try_get()
in several trait implementations for signals
This PR replaces the use of
get()
withtry_get()
for retrieving signal values in these trait implementations:IntoProperty
IntoClass
IntoStyle
Render
RenderHtml
AttributeValue
InnerHtmlValue
This change prevents potential panics when the signal is disposed.
As a result, I've replaced most
if let
blocks inRenderEffect
s withmatch
statements to handle different variations of the previous state and the signal value better.There are some match arms that don't make much sense to me, which usually happens when a signal is disposed, so I just returned
None
or the previous state if it was possible.