question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

State not working with custom component

See original GitHub issue

This issue is on iOS - not sure about Android.

1.0.137

I have the following simplified custom component, when I use it on a page the State doesn’t update:

class MyTestEntryState
{
    public string? Text { get; set; }
    public string? PlaceholderText { get; set; }
}

class MyTestEntry : Component<MyTestEntryState>
{
    public MyTestEntry Text(string? text)
    {
        SetState(state => state.Text = text);
        return this;
    }

    public MyTestEntry PlaceholderText(string? placeholderText)
    {
        SetState(state => state.PlaceholderText = placeholderText);
        return this;
    }

    public override Entry Render() => new Entry()
        .Text(State.Text ?? "")
        .Placeholder(State.PlaceholderText ?? "");
}

Render method on any Component Page:

  1. Enter value in Source, see that the State updates in the “Destination” Entry.
  2. Uncomment the custom component.
  3. Enter value in Source, see that State stops updating - neither “Custom Destination” nor “Destination” updates.
    public override VisualNode Render() => new ContentPage
    {
        new Grid("48, 48, 48", "*")
        {
            // new MyTestEntry()
            //     .PlaceholderText("Custom Destination")
            //     .Text(State.SearchText)
            //     .GridRow(0),

            new Entry()
                .Placeholder("Destination")
                .Text(State.SearchText ?? "")
                .GridRow(1),

            new Entry()
                .Placeholder("Source")
                .Text(State.SearchText ?? "")
                .OnTextChanged((s, e) => SetState(state => state.SearchText = e.NewTextValue))
                .GridRow(2)
        }
    };

Issue Analytics

  • State:closed
  • Created 2 months ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
adospacecommented, Jul 11, 2023

Hi, you can’t update the state like that (State is not yet ready at that moment). Try this instead:

class MyTestEntryState
{
    public string? Text { get; set; }
    public string? PlaceholderText { get; set; }
}

class MyTestEntry : Component<MyTestEntryState>
{
    string? _text;
    string? _placeholderText;
    public MyTestEntry Text(string? text)
    {
        _text = text;
        return this;
    }

    public MyTestEntry PlaceholderText(string? placeholderText)
    {
        _placeholderText = placeholderText;
        return this;
    }

    protected override OnMountedOrPropsChanged()
    {
       State.Text = _text;
       State.PlaceholderText = _placeholderText;
       base.OnMountedOrPropsChanged();
    }
   
    public override Entry Render() => new Entry()
        .Text(State.Text ?? "")
        .Placeholder(State.PlaceholderText ?? "");
}

BUT: from what I see you don’t need at all a stateful component, like this:

class MyTestEntry : Component
{
    string? _text;
    string? _placeholderText;
    public MyTestEntry Text(string? text)
    {
        _text = text;
        return this;
    }

    public MyTestEntry PlaceholderText(string? placeholderText)
    {
        _placeholderText = placeholderText;
        return this;
    }

    protected override OnMountedOrPropsChanged()
    {
       State.Text = _text;
       State.PlaceholderText = _placeholderText;
       base.OnMountedOrPropsChanged();
    }
   
    public override Entry Render() => new Entry()
        .Text(_text ?? "")
        .Placeholder(_placeholderText ?? "");
}

or even better, not using a Component, everything could be down to:

public static class Theme
{
    //custom Entry with font, size color etc, reusable 
    public static Entry Entry(string text, string? placeholder = null) 
       => new Entry()
          .Text(_text)
          .Placeholder(_placeholderText ?? "");
}

Why are you using a stateful component?

2reactions
adospacecommented, Jul 11, 2023

like this? TestMudEntry

class MainPageState
{
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

class MainPage : Component<MainPageState>
{
    public override VisualNode Render()
    {
        return new ContentPage
        {
            new VStack(spacing: 10)
            {
                new MudEntry()
                    .Label("First Name")
                    .OnTextChanged(text => SetState(s => s.FirstName = text)),

                new MudEntry()
                    .Label("Last Name")
                    .OnTextChanged(text => SetState(s => s.LastName = text)),
            }
            .HFill()
            .VCenter()
            .Margin(50)
        };
    }
}

class MudEntryState
{
    public bool Focused { get; set; }

    public bool IsEmpty { get; set; } = true;
}

class MudEntry : Component<MudEntryState>
{
    private MauiControls.Entry _entryRef;
    private Action<string> _textChangedAction;
    private string _label;

    public MudEntry OnTextChanged(Action<string> textChangedAction)
    {
        _textChangedAction = textChangedAction;
        return this;
    }

    public MudEntry Label(string label)
    {
        _label = label;
        return this;
    }

    public override VisualNode Render()
    {
        return new Grid("Auto", "*")
        {
            new Entry(entryRef => _entryRef = entryRef)
                .OnAfterTextChanged(OnTextChanged)
                .VCenter()
                .OnFocused(()=>SetState(s => s.Focused = true))
                .OnUnfocused(()=>SetState(s => s.Focused = false)),

            new Label(_label)                
                .OnTapped(()=>_entryRef?.Focus())
                .Margin(5,0)
                .HStart()
                .VCenter()
                .TranslationY(State.Focused || !State.IsEmpty ? -20 : 0)
                .ScaleX(State.Focused || !State.IsEmpty ? 0.8 : 1.0)
                .AnchorX(0)
                .TextColor(!State.Focused || State.IsEmpty ? Colors.Gray : Colors.Red)
                .WithAnimation(duration: 200),
        }
        .VCenter();
    }

    private void OnTextChanged(string text)
    {
        SetState(s => s.IsEmpty = string.IsNullOrWhiteSpace(text));
        _textChangedAction?.Invoke(text);
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

reactjs custom component input value doesnt update with ...
I am working on a list app, and I am having issues with the components not updating correctly. I pull the users list...
Read more >
Component local state not updating with react custom hooks
Hi All, I'm just starting to use react hooks and I'm having some issues when using custom hooks. It's probably lack of understanding...
Read more >
Custom component doesn't re-render an update state #38
I'm having hard time to update a props in a custom component and I finally though it's because I see it as a...
Read more >
How To Manage State on React Class Components
Learning the concepts behind state management will help you navigate and troubleshoot class-based state management in existing code bases ...
Read more >
Develop custom components
If Retool's built-in components don't work for your use case, you can build your own custom ... This allows the custom component to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found