Skip to content

Setting Default For Signal Props Is Verbose #3920

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

Open
DogeDark opened this issue Mar 26, 2025 · 4 comments · May be fixed by #3959
Open

Setting Default For Signal Props Is Verbose #3920

DogeDark opened this issue Mar 26, 2025 · 4 comments · May be fixed by #3959
Labels
enhancement New feature or request

Comments

@DogeDark
Copy link
Member

Request

If you have a ReadOnlySignal<bool> or Signal<bool>, it can be verbose to use the #[props(default = x)] syntax. For example:

#[derive(Props, Clone, PartialEq)]
pub struct SomeProps {

    // This sets bool to be false
    #[props(default)] 
    value: ReadOnlySignal<bool>,

    // This is what I'd like, except it wants a ReadOnlySignal
    #[props(default = true)] 
    value: ReadOnlySignal<bool>,

    // Instead you have to do this:
    #[props(default = ReadOnlySignal::new(Signal::new(true)))]
    value: ReadOnlySignal<bool>,

   // Same for signals:
   #[props(default = Signal::new(true))]
   value: Signal<bool>,
}

Implement Suggestion

Detect if the prop type is a ReadOnlySignal or Signal and automatically create boilerplate code, injecting the provided expression as the input to the ::new functions.

@DogeDark DogeDark added the enhancement New feature or request label Mar 26, 2025
@DogeDark DogeDark assigned DogeDark and unassigned DogeDark Mar 26, 2025
@pandarrr
Copy link

pandarrr commented Apr 4, 2025

Seems like it would not be hard to extend the props macro to recognize Signal/ReadOnlySignal and adjust the default accordingly. Something sort of similar is done for optionals.

If this is a something the team wants handled in the macro I can send a PR for it.

@ealmloff
Copy link
Member

ealmloff commented Apr 4, 2025

Seems like it would not be hard to extend the props macro to recognize Signal/ReadOnlySignal and adjust the default accordingly. Something sort of similar is done for optionals.

If this is a something the team wants handled in the macro I can send a PR for it.

That sounds like a good extension. If you want to work on a PR, keep in mind the signal we create in the props macro needs to be owned by the child component which means we need to call new inside of an owner in the builder. We have some logic for this already for converting T to ReadOnlySignal<T> here

@pandarrr
Copy link

pandarrr commented Apr 4, 2025

Interesting. I think there may be a bug related to defaults for ReadOnlySignal and Callback types then. When using the builder functions the value is owned but the child props, but there is not such logic for defaults.

Here is an example of how the default needs to be written currently and the build() method it expands to.

#[derive(Props)]
pub struct FormProps {
    #[props(default = ReadOnlySignal::new(Signal::new(false)))]
    pub read_only_signal: ReadOnlySignal<bool>,
}
#[allow(dead_code, non_camel_case_types, missing_docs)]
impl<
    __read_only_signal: FormPropsBuilder_Optional<ReadOnlySignal<bool>>,
> FormPropsBuilder<(__read_only_signal,)> {
    pub fn build(self) -> FormPropsWithOwner {
        let (read_only_signal,) = self.fields;
        let read_only_signal = FormPropsBuilder_Optional::into_value(
            read_only_signal,
            || ReadOnlySignal::new(Signal::new(false)),
        );
        FormPropsWithOwner {
            inner: FormProps { read_only_signal },
            owner: self.owner,
        }
    }
}

If I understand this right, the default value will be owned by the component where this is expanded. I think I actually encountered this bug last week using default Callbacks but didn't realize the cause and assumed I was misusing something. The callback would log a warning because it used a Signal owned by the child scope, but the callback itself was owned by the parent scope.

@pandarrr pandarrr linked a pull request Apr 6, 2025 that will close this issue
@pandarrr
Copy link

pandarrr commented Apr 6, 2025

I opened a PR for this. Because it's only building off the existing behavior of when a prop's builder method is called, it only applies to ReadOnlySignal and Callback types. I did not want to mess around with things too much for my first change.

If I understand this right, the default value will be owned by the component where this is expanded. I think I actually encountered this bug last week using default Callbacks but didn't realize the cause and assumed I was misusing something. The callback would log a warning because it used a Signal owned by the child scope, but the callback itself was owned by the parent scope.

I realized I was conflating Owner and Scope. The issue I was encountering is that when a Callback is executed it uses the scope it was created in, regardless of which owner it gets assigned. This is a separate issue (if it's an issue at all) and I've worked around it for now by creating by own callback type that always executes in the current scope, rather than its origin scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants