ProductiveRage / Bridge.React

Bindings for Bridge.NET for React - write React applications in C#!
MIT License
74 stars 14 forks source link

Arguments for lifecycle functions for stateful components are passed wrapped in a javascript objects #25

Closed Porl91 closed 7 years ago

Porl91 commented 7 years ago

The props / state arguments passed to stateful components 'ComponentDidUpdate', 'ComponentWillUpdate' and 'ShouldComponentUpdate' lifecycle methods are passed wrapped in a javascript object.

[Ready]
        public static void Main()
        {
            var container = Bridge.Html5.Document.GetElementById<HTMLDivElement>("react-main");

            React.Render(new TestComponent(1), container);
            React.Render(new TestComponent(2), container);
        }

        public class TestComponent : Component<TestComponent.Props, object>
        {
            public TestComponent(int testProp) : base(new Props(testProp)) { }

            protected override void ComponentDidUpdate(Props previousProps, object previousState)
            {
                Console.WriteLine("ComponentDidUpdate");
                Console.WriteLine(previousProps);
                Console.WriteLine(previousState);

                base.ComponentDidUpdate(previousProps, previousState);
            }

            protected override void ComponentWillUpdate(Props nextProps, object nextState)
            {
                Console.WriteLine("ComponentWillUpdate");
                Console.WriteLine(nextProps);
                Console.WriteLine(nextState);

                base.ComponentWillUpdate(nextProps, nextState);
            }

            protected override bool ShouldComponentUpdate(Props nextProps, object nextState)
            {
                Console.WriteLine("ShouldComponentUpdate");
                Console.WriteLine(nextProps);
                Console.WriteLine(nextState);

                return base.ShouldComponentUpdate(nextProps, nextState);
            }

            public override ReactElement Render()
            {
                return DOM.Div("bla");
            }

            public class Props : IAmImmutable
            {
                public Props(int testProp)
                {
                    this.CtorSet(_ => _.TestProp, testProp);
                }

                public int TestProp { get; }
            }
        }

The Console.WriteLine in the ShouldComponentUpdate method prints the following to the console:

Actual:

ShouldComponentUpdate
{
    "value": {
        "__TestProp_Lock": true,
        "TestProp": 2
    }
}
ComponentWillUpdate
{
    "value": {
        "__TestProp_Lock": true,
        "TestProp": 2
    }
}
ComponentDidUpdate
{
    "value": {
        "__TestProp_Lock": true,
        "TestProp": 1
    }
}

Expected:

ShouldComponentUpdate
{
    "TestProp": 2
}
ComponentWillUpdate
{
    "TestProp": 2
}
ComponentDidUpdate
{
    "TestProp": 1
}
Porl91 commented 7 years ago

Updated the issue to explain that this appears to affect all lifecycle functions for stateful (presumably also stateless) components that accept component properties / state as parameters.

ProductiveRage commented 7 years ago

This has been fixed and an updated (still pre-release, though this issue only affected the pre-release versions) package deployed to NuGet.

I think that this issue was also affecting the PureComponent's "ShouldComponentUpdate" implementation - essentially disabling it. I have added a unit test for this ("PureComponent re-rendered with equivalent props should not have to re-render") that failed before the fix and now passes.